Symptom
Round-tripping a TIMETZ value through example.echo strips the timezone
offset from the displayed/serialised value. The filter logic correctly
selects the row, but the value in the result row no longer carries +00
or whatever offset it had on input.
Reproduction
ATTACH 'example' AS example (TYPE vgi, LOCATION '${VGI_TEST_WORKER}');
-- DuckDB-native: row value renders as 12:00:00+00
SELECT t FROM (VALUES ('12:00:00+00'::TIMETZ)) v(t);
-- 12:00:00+00
-- Through example.echo: row value renders as 12:00:00 (offset lost)
SELECT t FROM example.echo((SELECT * FROM (VALUES ('12:00:00+00'::TIMETZ)) v(t)));
-- 12:00:00
Where to look
DuckDB.time_tz is registered as a canonical Arrow extension at
vgi/duckdb/src/common/arrow/arrow_type_extension.cpp:561
backed by fixed_size_binary(8). The echo passthrough rebuilds a
RecordBatch from the input batch on the way back. Probably the schema for
the rebuilt batch reports time64[us] (the canonical Arrow time type)
instead of preserving the extension<DuckDB.time_tz> wrapper, so DuckDB
on receive interprets the value as plain TIME and prints without the
offset.
The fix should keep the extension type marker on the rebuilt schema, so
the wire format declares extension<DuckDB.time_tz> and DuckDB knows to
unpack the offset on read.
Coverage gap
Uncovered today; surfaced while writing
vgi/test/sql/integration/filter_pushdown/time_tz.test.
That test now selects only the row id (SELECT n FROM ...) to sidestep
this display issue. A time_tz_roundtrip.test that verifies the value
round-trips with offset intact would catch this.
Priority
Low-to-medium — only affects display, not correctness of filtering. But
if downstream consumers depend on TIMETZ values carrying their original
offset, this silently corrupts that.
Symptom
Round-tripping a TIMETZ value through
example.echostrips the timezoneoffset from the displayed/serialised value. The filter logic correctly
selects the row, but the value in the result row no longer carries
+00or whatever offset it had on input.
Reproduction
Where to look
DuckDB.time_tzis registered as a canonical Arrow extension atvgi/duckdb/src/common/arrow/arrow_type_extension.cpp:561backed by
fixed_size_binary(8). The echo passthrough rebuilds aRecordBatch from the input batch on the way back. Probably the schema for
the rebuilt batch reports
time64[us](the canonical Arrow time type)instead of preserving the
extension<DuckDB.time_tz>wrapper, so DuckDBon receive interprets the value as plain TIME and prints without the
offset.
The fix should keep the extension type marker on the rebuilt schema, so
the wire format declares
extension<DuckDB.time_tz>and DuckDB knows tounpack the offset on read.
Coverage gap
Uncovered today; surfaced while writing
vgi/test/sql/integration/filter_pushdown/time_tz.test.That test now selects only the row id (
SELECT n FROM ...) to sidestepthis display issue. A
time_tz_roundtrip.testthat verifies the valueround-trips with offset intact would catch this.
Priority
Low-to-medium — only affects display, not correctness of filtering. But
if downstream consumers depend on TIMETZ values carrying their original
offset, this silently corrupts that.