Doris-Breakwater commented on issue #67367:
URL: https://github.com/apache/doris/issues/67367#issuecomment-5490616776

   Breakwater-GitHub-Analysis-Slot: slot_0480a2cd30b5
   
   ## Initial triage
   
   This should be treated as a correctness bug, not only a client-display 
issue: a persisted JSON object is reported as a different, valid string value 
on the first read. The identical Arrow schema on the bad and good executions 
(`int32, string, string`), together with both nullable and non-nullable columns 
being affected, makes an Arrow type mismatch or outer-nullability handling 
unlikely.
   
   The proposed root cause (stale table/schema metadata held by the 
pre-existing Flight SQL connection) is **not yet established**. In the supplied 
sequence, the new-connection control runs only after the old connection has 
executed the query twice. It therefore changes both connection age and query 
order: a first-reader/storage initialization or timing effect could produce the 
same observation.
   
   ## What the 4.1.3-rc02 code supports
   
   I inspected commit `31263df4dc1d4d3a27517d264802cd4d6b92c874` read-only.
   
   * The Flight SQL path resets its result channel for each statement and 
constructs a new processor/executor. I did not find a per-connection 
table-schema snapshot in `FlightSqlConnectContext`, `DorisFlightSqlProducer`, 
or `FlightSqlConnectProcessor` that would directly explain a table created 
after connection establishment.
   * `CAST(VARIANT AS STRING)` is evaluated before the Arrow result conversion. 
The Flight result writer receives an ordinary Doris string column, so Arrow 
schema metadata alone cannot turn `{}` into an empty string.
   * The V1 `ColumnVariant` serializer explicitly emits `{}` when a row has no 
visible paths, and the hierarchical reader comments/code preserve an empty root 
placeholder as a present empty object rather than SQL `NULL`.
   * The V2 assembler has the same explicit rule: an empty whole-Variant row is 
`{}`, while an absent subtree is SQL `NULL`.
   * Unit coverage exists for the isolated empty-object assembly semantics, but 
I did not find an end-to-end regression covering persisted scan -> 
Variant-to-string cast -> Flight result on the first query.
   
   These are verified code-path facts, but they do not identify the component 
that first produces the zero-length value. The remaining hypotheses include a 
first-read storage/Variant initialization path, a session-state difference, and 
the ADBC/Arrow conversion boundary. There is currently insufficient evidence to 
rank one as the root cause.
   
   ## Information needed to isolate the fault
   
   Please attach:
   
   1. Exact versions of `adbc_driver_flightsql`, PyArrow, and the Arrow C++ 
libraries used by the driver.
   2. Whether the failure is deterministic, its frequency over clean-table 
repetitions, and whether delaying the first Flight query changes it.
   3. `SHOW CREATE TABLE`, FE/BE topology and deployment mode, plus the 
effective Variant settings—especially `enable_variant_v2` and the table's 
document/hierarchical-storage settings. Please do not infer these from release 
defaults.
   4. Query IDs for the first bad and second good executions, with the 
corresponding FE/BE logs and query profiles. A profile pair is useful even when 
runtimes are similar because it identifies the scan instance and result-sink 
path.
   5. The result of a diagnostic query that returns the cast value together 
with `LENGTH(...)` and `HEX(...)` on the first execution. If the 
server-computed length is already `0`, the fault precedes Arrow string-buffer 
materialization; if it is `2` while the fetched value is empty, focus on the 
Flight/ADBC boundary.
   
   The most important reproduction control is to remove the query-order 
confounder after each fresh table creation:
   
   * Make a connection opened **after** the insert the very first reader, 
before the pre-existing connection runs anything.
   * In a separate repetition, make the pre-existing connection the first 
reader.
   * Before any Flight query, run the exact `CAST(... AS STRING)` query over 
MySQL/JDBC and record `LENGTH`/`HEX` as a storage/control-path check.
   * Repeat with a non-empty object such as `{"a":1}` and an empty array to 
determine whether this is specific to the empty-object root placeholder.
   
   ## Suggested maintainer next steps
   
   Reproduce on the reported commit with the controlled ordering above, then 
inspect the value at three boundaries for the bad query ID: after Variant row 
assembly, after `VARIANT -> STRING` serialization, and immediately before the 
Doris block is converted to an Arrow batch. The first boundary at which the 
bytes change from `7b 7d` to zero length will determine ownership without 
assuming a connection cache.
   
   Once isolated, add an end-to-end regression that opens the Flight connection 
before DDL, persists `{}`, and asserts the first read, repeated read, and first 
read from a second connection. A lower-level persisted-segment scan/cast test 
should accompany it if the corruption is already present before the result sink.
   
   Retrying or reconnecting is a reasonable temporary workaround, but a silent 
retry would mask a correctness failure and should not be considered the fix. 
This issue can remain linked to #65615, but it should not be closed as a 
duplicate without identifying the failing boundary. No labels are currently 
attached; `kind/bug`, `area/rpc`, and the repository's existing VARIANT/storage 
ownership label (if available) would make routing clearer.
   


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