Search before asking
Version
master (ddbaaab1388)
What's Wrong?
Doris writes year-zero DATETIME values to Parquet correctly, but cannot read its own file back — the values come back NULL.
be/src/core/data_type_serde/parquet_timestamp.h gates every Parquet timestamp read at year 1:
inline constexpr int64_t MIN_DORIS_TIMESTAMP_MICROS = -62135596800000000LL; // 0001-01-01
inline constexpr int64_t MAX_DORIS_TIMESTAMP_MICROS = 253402300799999999LL; // 9999-12-31
inline Status validate_parquet_timestamp_micros(int64_t timestamp_micros) {
if (timestamp_micros < MIN_DORIS_TIMESTAMP_MICROS || timestamp_micros > MAX_DORIS_TIMESTAMP_MICROS) {
return Status::DataQualityError(
"Parquet timestamp is outside the Doris 0001-9999 range: micros={}", timestamp_micros);
}
return Status::OK();
}
But the DATETIME type itself starts at 0000-01-01, whose micros value is -62167219200000000 — below that bound. So the reader is stricter than the type it materialises into.
What You Expected?
A DATETIME value that Doris accepts, stores and exports should read back from Doris's own Parquet file.
How to Reproduce?
CREATE TABLE dt0 (id INT, ts DATETIME(6)) DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 1 PROPERTIES('replication_num'='1');
INSERT INTO dt0 VALUES (1,'0000-01-01 12:34:56'),(2,'0000-03-01 00:00:00'),
(3,'1969-12-31 23:59:59'),(4,'2024-01-01 12:00:00');
-- the type stores them fine
SELECT id, CAST(ts AS STRING) FROM dt0 ORDER BY id;
-- 1 0000-01-01 12:34:56.000000
-- 2 0000-03-01 00:00:00.000000
-- 3 1969-12-31 23:59:59.000000
-- 4 2024-01-01 12:00:00.000000
SELECT * FROM dt0 ORDER BY id INTO OUTFILE 'file:///tmp/dtz/p_' FORMAT AS PARQUET;
Read the file back with the local() TVF:
id ts_read
1 NULL <-- lost
2 NULL <-- lost
3 1969-12-31 23:59:59.000000
4 2024-01-01 12:00:00.000000
Note 0000-03-01 is also lost, so this is a plain range check, not a calendar edge case.
Anything Else?
The write side is correct: Spark reads the same year-zero timestamps out of a Doris-written Iceberg table without trouble (verified with apache/spark:4.0.0 against the Iceberg REST catalog — Spark returned 0000-01-01 12:34:56 for the row Doris returned NULL for). So only Doris's reader rejects them.
The constant name and the error text both say 0001-9999, so the bound may be deliberate. If so, the asymmetry is still worth resolving in one direction or the other:
- widen the reader to
0000-01-01 (-62167219200000000) to match the DATETIME range, or
- reject year-zero timestamps on the write path too, so Doris never produces a file it cannot read.
Found while running Iceberg regression suites for #67366.
Are you willing to submit PR?
Code of Conduct
Search before asking
Version
master (
ddbaaab1388)What's Wrong?
Doris writes year-zero
DATETIMEvalues to Parquet correctly, but cannot read its own file back — the values come backNULL.be/src/core/data_type_serde/parquet_timestamp.hgates every Parquet timestamp read at year 1:But the DATETIME type itself starts at
0000-01-01, whose micros value is-62167219200000000— below that bound. So the reader is stricter than the type it materialises into.What You Expected?
A
DATETIMEvalue that Doris accepts, stores and exports should read back from Doris's own Parquet file.How to Reproduce?
Read the file back with the
local()TVF:Note
0000-03-01is also lost, so this is a plain range check, not a calendar edge case.Anything Else?
The write side is correct: Spark reads the same year-zero timestamps out of a Doris-written Iceberg table without trouble (verified with
apache/spark:4.0.0against the Iceberg REST catalog — Spark returned0000-01-01 12:34:56for the row Doris returnedNULLfor). So only Doris's reader rejects them.The constant name and the error text both say
0001-9999, so the bound may be deliberate. If so, the asymmetry is still worth resolving in one direction or the other:0000-01-01(-62167219200000000) to match the DATETIME range, orFound while running Iceberg regression suites for #67366.
Are you willing to submit PR?
Code of Conduct