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

   ### What problem does this PR solve?
   
   Related Jira: DORIS-28389
   
   Problem Summary:
   
   Arrow has no equivalent for LARGEINT, IPV4, IPV6, JSON or VARIANT. Each of 
them travels over Flight SQL as some other Arrow type and is then 
indistinguishable from a column that is natively of that type -- a LARGEINT and 
a STRING both arrive as `utf8`, an IPV4 and an INT both arrive as `int32`. The 
`doris_type` field metadata is the only thing that tells them apart.
   
   That metadata was attached in `get_arrow_schema_from_block` and 
`get_arrow_schema_from_expr_ctxs`, which only see the top level columns. 
`convert_to_arrow_type` recurses into ARRAY / MAP / STRUCT building Arrow 
**types**, and Arrow keeps metadata on the `Field` rather than on the 
`DataType`, so every nested element lost it: `ListType(item_type)` synthesizes 
a bare `"item"` field, `MapType(key_type, val_type)` synthesizes bare 
`"key"`/`"value"` fields, and the STRUCT branch built its fields without going 
through the metadata helper.
   
   Reading this through a Python ADBC client:
   
   ```sql
   SELECT CAST(495 AS LARGEINT)                        AS scalar_value,
          named_struct('count', CAST(495 AS LARGEINT)) AS struct_value,
          array(CAST(495 AS LARGEINT))                 AS array_value,
          map('k', CAST(495 AS LARGEINT))              AS map_value;
   ```
   
   **Before** -- only the top level column is identifiable:
   
   ```
   scalar_value: string   metadata={'doris_type': 'LARGEINT'}
   struct_value: struct<count: string>
     count: string        metadata={}
   array_value: list<item: string>
     item: string         metadata={}
   map_value: map<string, string>
     entries: struct<key: string not null, value: string>
       key: string        metadata={}
       value: string      metadata={}
   ```
   
   **After**:
   
   ```
   scalar_value: string   metadata={'doris_type': 'LARGEINT'}
   struct_value: struct<count: string>
     count: string        metadata={'doris_type': 'LARGEINT'}
   array_value: list<item: string>
     item: string         metadata={'doris_type': 'LARGEINT'}
   map_value: map<string, string>
     entries: struct<key: string not null, value: string>
       key: string        metadata={}
       value: string      metadata={'doris_type': 'LARGEINT'}
   ```
   
   A nested IPV4 was the worse case of the same defect: it arrives as its 32 
bits read as a signed `int32` (`192.168.1.1` as `-1062731519`) with nothing 
left to say it was ever an address.
   
   ### What is changed?
   
   `convert_to_arrow_type` now builds the child `Field`s through 
`create_arrow_field_with_metadata` at every level, for ARRAY, MAP and STRUCT. 
The names and the nullability are exactly the ones Arrow's own constructors 
produced -- `"item"` nullable, `"key"` non-nullable, `"value"` nullable -- so 
**only the metadata is new**, and the record batch builders, which are made 
from this same schema (`FromBlockToRecordBatchConverter` reads 
`_schema->field(idx)->type()`), are unaffected. `DataType::Equals` ignores 
metadata by default, so the batch still type-matches the schema.
   
   The metadata lookup is also completed: JSONB and VARIANT are serialized as 
`utf8` too and were carrying no `doris_type` at all, not even at the top level. 
The values (`JSON`, `VARIANT`) match what the FE reports for the same column 
under `ARROW:FLIGHT:SQL:TYPE_NAME` in `FlightSqlSchemaHelper`.
   
   No value or Arrow type changes -- this is metadata only.
   
   ### Release note
   
   Fix Arrow Flight SQL losing the Doris logical type (`doris_type` field 
metadata) of LARGEINT / IPV4 / IPV6 nested inside STRUCT, ARRAY and MAP, which 
made a nested LARGEINT indistinguishable from a STRING for ADBC clients. JSON 
and VARIANT columns now carry the same metadata as well.
   
   ### Check List (For Author)
   
   - Test
       - [x] Unit Test
   
     New `be/test/format/arrow/arrow_row_batch_test.cpp`, 7 cases:
     nested LARGEINT in STRUCT / ARRAY / MAP value / MAP key; every level of
     `array<struct<largeint>>` and `map<string, array<array<largeint>>>`;
     nested IPV4 / IPV6 / JSON / VARIANT; a negative control asserting STRING 
and
     INT carry no metadata nested or not; an assertion that the nested types 
still
     compare equal to `arrow::list(utf8())` / `arrow::map(utf8(), utf8())` with
     `check_metadata=false` and differ only with `check_metadata=true`; and one
     that runs `convert_to_arrow_batch` over the new schema and checks
     `ValidateFull()`, schema equality including metadata, and the values.
   
     Verified the assertions are not vacuous: with the `arrow_row_batch.cpp` 
change
     reverted, 5 of the 7 fail; the negative control and the batch-building 
guard
     correctly stay green.
   
       - [x] Manual test (add detailed scripts or steps below)
   
     Built BE locally and ran the Jira's repro through
     `adbc_driver_flightsql` (Python), plus a real table with
     `largeint`, `array<largeint>`, `struct<count:largeint, name:string>`,
     `map<string,largeint>`, `ipv4` and `json` columns. Nested fields now carry
     `doris_type` at every depth, a STRING sibling inside the same STRUCT 
correctly
     carries none, and the values are unchanged (LARGEINT extremes round trip
     losslessly as text).
   
   - Behavior changed:
       - [x] Yes.
   
     The Arrow schema returned over Flight SQL now carries `doris_type` field
     metadata on nested fields, and on top level JSON / VARIANT columns. Arrow
     types, field names, nullability and values are unchanged, so a client that
     ignores metadata sees no difference.
   
   - Does this need documentation?
       - [x] No.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   
   https://claude.ai/code/session_01FP36MDAsUyKSSDQXQohQsK
   


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