Repository navigation
Description
Search before asking
- I had searched in the issues and found no similar issues.
Version
Apache Doris 4.1.3-rc02, commit 31263df4dc1d4d3a27517d264802cd4d6b92c874
Client: Python + ADBC Flight SQL driver (adbc_driver_flightsql), FE arrow_flight_sql_port = 41070.
The MySQL/JDBC protocol is used as the control path for comparison.
What's Wrong?
Doris MAP semantics allow a NULL key, but the Arrow MAP specification requires the key field to be non-nullable. When a result contains a NULL map key, the Flight SQL DoGet fails and the whole result becomes unreadable:
Can not write null value of map key to arrow
Projecting the same value as map_entries(m), i.e. ARRAY<STRUCT<key, value>>, is returned over ADBC correctly and preserves the NULL key.
What You Expected?
Flight SQL should be able to return MAP data that Doris itself accepts, either through a compatible Arrow representation that preserves the NULL key, or with a clear, documented limitation; it should not fail the entire result at DoGet time.
How to Reproduce?
- Create a Doris table with a
MAP<STRING,INT>column. - Insert
map(NULL,100). - Query the raw
MAPcolumn over Python ADBC;DoGetfails. - Query
map_entries(m); the same data is returned through the compatible structure.
DROP TABLE IF EXISTS adbc_null_map;
CREATE TABLE adbc_null_map (
k INT,
m MAP<STRING,INT>
) DUPLICATE KEY(k)
DISTRIBUTED BY HASH(k) BUCKETS 1
PROPERTIES("replication_num"="1");
INSERT INTO adbc_null_map VALUES (1, map(NULL,100));
-- Fails through Arrow Flight SQL.
SELECT m FROM adbc_null_map;
-- Succeeds and preserves the NULL key.
SELECT map_entries(m) FROM adbc_null_map;Client side:
import adbc_driver_flightsql.dbapi as flight_sql
conn = flight_sql.connect(uri="grpc://127.0.0.1:41070",
db_kwargs={"username": "root", "password": ""})
cur = conn.cursor()
cur.execute("SELECT m FROM adbc_null_map")
cur.fetch_arrow_table()Anything Else?
This is a genuine model mismatch between Doris MAP and Arrow MAP, so it needs an explicit decision rather than only a test skip: either serialize such maps as list<struct<key, value>> (which round-trips the NULL key, as map_entries already shows), or reject them with a clear, documented error at plan/schema time instead of failing mid-stream in DoGet. Either way the limitation belongs in the Arrow Flight SQL documentation.
Related: #65182 skipped the Arrow-incompatible Map null-key regression cases; this issue tracks the underlying behavior.
Workaround: use map_entries(m) in SQL to project the MAP as ARRAY<STRUCT<key, value>>, or filter/replace NULL keys when the business logic allows it.
Tracking issue: #65615
Are you willing to submit PR?
- Yes I am willing to submit a PR!
Code of Conduct
- I agree to follow this project's Code of Conduct
Activity
Doris-Breakwater commentedon Sep 1, 2026
Breakwater-GitHub-Analysis-Slot: slot_ad34727ee091
Initial triage
This is a confirmed server-side type-model incompatibility, not an ADBC/PyArrow client issue. The supplied reproducer is sufficient for triage, and source inspection at
31263df4dc1d4d3a27517d264802cd4d6b92c874matches the reported error exactly. One NULL key makes the affectedDoGetstream unreadable, although it does not mutate or corrupt stored data. The documentedmap_entries(m)workaround is lossless for this case.The issue currently has no labels. Suggested labels are
kind/bugandarea/rpc; it is also already indexed by #65615.Verified mechanism
convert_to_arrow_type()maps every DorisTYPE_MAPtoarrow::MapTypebased only on the expression type.init()/prepare(), before result rows are available.DoGet; for example, the local reader callsconvert_to_arrow_batch()only after fetching a result block.DataTypeMapSerDe::write_column_to_arrow()inspects the actual key null map at that point and returnsINVALID_ARGUMENTwith the exact reported message when it finds a NULL key.This is required by Arrow's MAP layout: the Arrow format states that neither the
entriesfield nor thekeyfield may be nullable (Arrow schema definition). Doris, by contrast, deliberately stores MAP keys in nullable child columns;map()also constructs a nullable key type. Static inspection of the current localmasterstill finds the same rejection path, so there is no apparent master-side fix yet, although I did not run a live cluster reproduction.map_entries(m)works for a concrete reason: it changes the Doris result type toARRAY<STRUCT<key, value>>, and its key struct field is nullable. Arrow then receives a List/Struct schema rather than logical MAP, so the NULL key is representable.Design constraints and recommendation
A per-row or per-batch fallback from Arrow MAP to List/Struct is not valid: the Flight stream schema is established before batches and must remain stable. Similarly, rejecting only MAPs that will contain a NULL key at plan/schema time is generally not possible from the current Doris type alone; determining that for a table result requires inspecting data. A type-time rejection would therefore have to reject all raw MAP outputs (or introduce a stronger non-null-key contract), including maps whose actual keys are valid for Arrow.
The maintainer decision should therefore be explicit and query-wide:
list<struct<key nullable, value nullable>>for Flight SQL, or initially expose that mapping behind an explicit connection/session compatibility option. This changes the client-visible Arrow type for existing non-NULL maps, so it needs a compatibility and release-note decision.map_entries(). Document that Doris MAP values containing NULL keys are not representable. Do not silently drop, replace, or filter NULL-key entries.Whichever policy is chosen, the stale comment in
DataTypeMapSerDesaying the NULL entry is ignored should be corrected; the implementation returns an error.Missing information
No additional logs, profile, or client metadata are needed to establish this mechanism. The exact
adbc_driver_flightsqland PyArrow versions would only be useful for pinning an end-to-end regression environment, not for determining the root cause. Runtime confirmation on currentmasterremains useful before closing the issue, but it is not blocking design or implementation.Suggested next steps
arrow_flight_sqlregression using the provided table case; assert both the returned Arrow schema and preservation of the NULL key under the chosen policy.