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?
When reading a mapped Iceberg TIMESTAMPTZ column with the session time_zone set to UTC, Doris Flight SQL returns the Arrow type timestamp[s, tz=Z].
PyArrow treats the timezone string as a zoneinfo key, so to_pylist() raises ZoneInfoNotFoundError because Z is not a valid IANA time zone name. The underlying epoch values themselves are correct: [1735704000, null, 939528000, null]. Rewriting only the schema metadata from Z to UTC leaves the epochs unchanged and makes the conversion succeed.
What You Expected?
UTC timezone metadata should use a name that PyArrow / zoneinfo can resolve (e.g. UTC, or a fixed +00:00 offset), so that to_pylist() returns UTC datetimes directly.
How to Reproduce?
- Bring up the Iceberg regression fixture and create a catalog with
"enable.mapping.timestamp_tz" = "true". SWITCHto that catalog,USE test_timestamp_tz, and set the sessiontime_zonetoUTC.- Read
test_ice_timestamp_tz_orcover Python ADBC Flight SQL. - Inspect the Arrow schema and call
to_pylist().
SWITCH test_iceberg_timestamp_tz_with_mapping;
USE test_timestamp_tz;
SET time_zone = 'UTC';
SELECT * FROM test_ice_timestamp_tz_orc ORDER BY id;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("SET time_zone = 'UTC'")
cur.execute("SELECT * FROM test_iceberg_timestamp_tz_with_mapping."
"test_timestamp_tz.test_ice_timestamp_tz_orc ORDER BY id")
table = cur.fetch_arrow_table()
print(table.schema) # timestamp[s, tz=Z]
print(table.to_pylist()) # ZoneInfoNotFoundErrorAnything Else?
Z is valid ISO-8601 offset syntax but is not a portable Arrow timezone string; the Arrow spec expects either an IANA name or a fixed +HH:MM offset. The Doris session time_zone value is apparently passed through to the Arrow field metadata verbatim.
Workaround: on the client, cast only the Arrow timezone metadata from Z to UTC before converting to Python; this does not change the epoch values. Casting to STRING in SQL also works, but loses the native TIMESTAMPTZ Arrow type.
Found with the external_table_p0/iceberg/test_iceberg_timestamp_tz fixture and confirmed with a raw Arrow probe plus a metadata-only cast.
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_71f66e5c4174
Initial maintainer assessment
Disposition: Accept as an Arrow Flight SQL interoperability bug. The report contains a complete version and reproduction, and the epoch values plus metadata-only workaround strongly indicate a schema-annotation problem rather than TIMESTAMPTZ value corruption. The impact is still user-visible: a standard Python Arrow conversion fails even though the query data is otherwise correct.
The issue is currently unlabeled and unassigned. Suggested labels are
kind/bugandarea/rpc; the Iceberg fixture exposes the problem, but the failing code path is the generic Flight SQL Arrow schema builder rather than Iceberg decoding.Code-path findings at
31263df4dc1d4d3a27517d264802cd4d6b92c874Verified facts:
FlightInfo; it does not reconstruct the TIMESTAMPTZ field itself (FlightSqlConnectProcessor.java,DorisFlightSqlProducer.java).RuntimeState::timezone()intoget_arrow_schema_from_expr_ctxs()(result_sink_operator.cpp). ForTYPE_TIMESTAMPTZ,convert_to_arrow_type()constructsarrow::TimestampType(time_unit, timezone)with that string unchanged (arrow_row_batch.cpp). There is no Arrow-specific validation or normalization at this boundary.ZoneId.of(...).getId()before putting it inTQueryGlobals(Coordinator.java,TimeUtils.java). Java canonicalization returnsZfor the valid Doris fixed-offset session value+00:00. Doris BE also recognizesZas Zulu, so that identifier can reach schema construction successfully.+XX:XX/-XX:XXoffset.Zis neither form. Consequently, emittingtimestamp[..., tz=Z]is non-portable and PyArrow'sZoneInfoNotFoundErroris consistent with the schema (Arrow timestamp format contract).This verifies the root-cause boundary: a timezone identifier valid within Doris/Java can be copied into an Arrow schema even when it is not a valid Arrow timezone identifier. It also proves a deterministic failure path for a session timezone of
+00:00.One detail remains unverified: at this exact commit,
TimeUtils.getCanonicalTimeZone("UTC")evaluates toUTC, notZ. Therefore the report's literalSET time_zone = 'UTC'should not be assumed to be the precise origin ofZwithout observing the effective value on the same Flight session. This discrepancy does not invalidate the reported server output or the generic bug, but it matters for identifying every upstream trigger and choosing regression coverage.Missing evidence for the exact
UTC -> ZtriggerPlease add the following from the same ADBC connection and cursor, immediately before the failing query:
SHOW VARIABLES LIKE 'time_zone'(not only confirmation thatSETreturned successfully).repr(table.schema.field(<timestamptz-column>).type.tz)for a small matrix of session values:UTC,+00:00, andAsia/Shanghai.pyarrow,adbc_driver_flightsql, and Python versions. These are not needed to accept the server-side metadata bug, but they make the client failure reproducible.UTCwhile the wire schema still containsZ.A Doris execution profile is not needed for this issue; this is schema construction, not a performance or operator-timing problem.
Recommended next steps
Zto the portableUTC(or+00:00) while leaving epoch buffers unchanged and preserving valid IANA names/non-zero fixed offsets.TYPE_TIMESTAMPTZArrow type construction coveringUTC,Z,+00:00, a non-zero offset, and an IANA zone. Because conversion is recursive, include at least one nested TIMESTAMPTZ case.SET time_zone = 'UTC'andSET time_zone = '+00:00'that asserts the wire-schema timezone and callsto_pylist()on nullable TIMESTAMPTZ values. Existing Flight SQL coverage checks JDBC type identity but does not assert timezone metadata portability.Doris-Breakwater commentedon Sep 1, 2026
Breakwater-GitHub-Analysis-Slot: slot_71f66e5c4174
Initial maintainer assessment
Disposition: Accept as an Arrow Flight SQL interoperability bug. The report contains a complete version and reproduction, and the epoch values plus metadata-only workaround strongly indicate a schema-annotation problem rather than TIMESTAMPTZ value corruption. The impact is still user-visible: a standard Python Arrow conversion fails even though the query data is otherwise correct.
The issue is currently unlabeled and unassigned. Suggested labels are
kind/bugandarea/rpc; the Iceberg fixture exposes the problem, but the failing code path is the generic Flight SQL Arrow schema builder rather than Iceberg decoding.Code-path findings at
31263df4dc1d4d3a27517d264802cd4d6b92c874Verified facts:
FlightInfo; it does not reconstruct the TIMESTAMPTZ field itself (FlightSqlConnectProcessor.java,DorisFlightSqlProducer.java).RuntimeState::timezone()intoget_arrow_schema_from_expr_ctxs()(result_sink_operator.cpp). ForTYPE_TIMESTAMPTZ,convert_to_arrow_type()constructsarrow::TimestampType(time_unit, timezone)with that string unchanged (arrow_row_batch.cpp). There is no Arrow-specific validation or normalization at this boundary.DataTypeTimeStampTzSerDe::write_column_to_arrow()converts every non-null value to a Unix epoch usingcctz::utc_time_zone()(data_type_timestamptz_serde.cpp). This matches the report's correct raw epochs and supports treating the defect as metadata-only.ZoneId.of(...).getId()before putting it inTQueryGlobals(Coordinator.java,TimeUtils.java). Java canonicalization returnsZfor the valid Doris fixed-offset session value+00:00. Doris BE also recognizesZas Zulu, so that identifier can reach schema construction successfully.+XX:XX/-XX:XXoffset.Zis neither form. Consequently, emittingtimestamp[..., tz=Z]is non-portable and PyArrow'sZoneInfoNotFoundErroris consistent with the schema (Arrow timestamp format contract).This verifies the root-cause boundary: a timezone identifier valid within Doris/Java can be copied into an Arrow schema even when it is not a valid Arrow timezone identifier. It also proves a deterministic failure path for a session timezone of
+00:00.One detail remains unverified: at this exact commit,
TimeUtils.getCanonicalTimeZone("UTC")evaluates toUTC, notZ. Therefore the report's literalSET time_zone = 'UTC'should not be assumed to be the precise origin ofZwithout observing the effective value on the same Flight session. This discrepancy does not invalidate the reported server output or the generic bug, but it matters for identifying every upstream trigger and choosing regression coverage.Missing evidence for the exact
UTC -> ZtriggerPlease add the following from the same ADBC connection and cursor, immediately before the failing query:
SHOW VARIABLES LIKE 'time_zone'(not only confirmation thatSETreturned successfully).repr(table.schema.field(<timestamptz-column>).type.tz)for a small matrix of session values:UTC,+00:00, andAsia/Shanghai.pyarrow,adbc_driver_flightsql, and Python versions. These are not needed to accept the server-side metadata bug, but they make the client failure reproducible.UTCwhile the wire schema still containsZ.A Doris execution profile is not needed for this issue; this is schema construction, not a performance or operator-timing problem.
Recommended next steps
Zto the portableUTC(or+00:00) while leaving epoch buffers unchanged and preserving valid IANA names/non-zero fixed offsets.TYPE_TIMESTAMPTZArrow type construction coveringUTC,Z,+00:00, a non-zero offset, and an IANA zone. Because conversion is recursive, include at least one nested TIMESTAMPTZ case.SET time_zone = 'UTC'andSET time_zone = '+00:00'that asserts the wire-schema timezone and callsto_pylist()on nullable TIMESTAMPTZ values. Existing Flight SQL coverage checks JDBC type identity but does not assert timezone metadata portability.