Skip to content

Extend the supported range of Date32 to [0000-01-01, 9999-12-31] - #111534

Merged
alexey-milovidov merged 41 commits into
masterfrom
extend-date32-range
Aug 12, 2026
Merged

Extend the supported range of Date32 to [0000-01-01, 9999-12-31]#111534
alexey-milovidov merged 41 commits into
masterfrom
extend-date32-range

Conversation

@alexey-milovidov

Copy link
Copy Markdown
Member

Changelog category (leave one):

  • Backward Incompatible Change

Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):

Extended the supported range of Date32 from [1900-01-01, 2299-12-31] to [0000-01-01, 9999-12-31], matching DateTime64. Parsing and conversions now accept the extended range instead of silently clamping to the old boundaries. Backward compatibility notes: in the numeric conversion toDate32(N), values in [120530, 2932896] are now interpreted as day numbers (dates from 2300-01-01 to 9999-12-31) instead of Unix timestamps in early 1970, matching the rule that a number that fits into the day-number range is a day number; numbers below the day number of 0000-01-01 and timestamps after 9999-12-31 saturate to the new boundaries.

Date32 was documented as [1900-01-01, 2299-12-31] — the span covered by the DateLUTImpl lookup table — while #107907 extended DateTime64 to [0000-01-01, 9999-12-31]. The mismatch was also internally inconsistent: parsing clamped silently while casting from the extended DateTime64 produced out-of-range Date32 values that rendered correctly:

SELECT toDate32('0079-08-24');                              -- 1900-01-01 (clamped)
SELECT age('year', toDate32('0079-08-24'), today());        -- 126 (plausible-looking wrong answer)
SELECT toDate32(toDateTime64('0079-08-24 13:00:00', 0));    -- 0079-08-24 (not clamped)

Now all three agree: the parse returns 0079-08-24 and age returns 1946.

Implementation: DateLUTImpl::makeDayNum / tryToMakeDayNum fall back to the cctz-based makeDayNumOutOfRange for valid calendar dates outside the LUT years, exactly like makeDateTime already does since #107907 — this single change covers text parsing everywhere (SQL casts from String, CSV/JSON/TSV/Values formats, YYYYMMDDToDayNum). Computations over extended values were already handled by the #107907 infrastructure, which gates every ExtendedDayNum argument with a cctz escape path; Date semantics are unchanged (its clamps happen downstream on the day-number result). The LUT-derived DATE_LUT_MAX_EXTEND_DAY_NUM (120530, exclusive) is replaced by inclusive DATE_LUT_MIN_EXTEND_DAY_NUM / DATE_LUT_MAX_EXTEND_DAY_NUM (−719528 / 2932896) tied to the internal representable window by static asserts. MAX_DATE32_TIMESTAMP is lifted to 9999-12-31 23:59:59. The monotonicity analysis threshold is kept in sync, the Parquet / Arrow / Arrow IPC / native ORC readers validate Date32 against the new bounds (also fixing an off-by-one that accepted day number 120530), and makeDate32 / YYYYMMDDToDate32 / changeDate accept years [0, 9999]. The default value of Date32 and the result of toDate32OrZero on unparseable input remain 1900-01-01.

Closes #111524
Related: #107907

Documentation entry for user-facing changes

  • Documentation is written (mandatory for new features)

`Date32` was limited to `[1900-01-01, 2299-12-31]` - the span covered by
the `DateLUTImpl` lookup table - while `DateTime64` was already extended
to `[0000-01-01, 9999-12-31]`. The mismatch was inconsistent on its own:
parsing `toDate32('0079-08-24')` silently clamped to `1900-01-01` (so
e.g. `age` returned a plausible-looking wrong answer), while the cast
`toDate32(toDateTime64('0079-08-24 13:00:00', 0))` produced the correct
out-of-range value, because the `Int32` day number has room for it and
the extended formatting path is shared with `DateTime64`.

`DateLUTImpl::makeDayNum` and `tryToMakeDayNum` now fall back to the
cctz-based `makeDayNumOutOfRange` for valid calendar dates outside
`[DATE_LUT_MIN_YEAR, DATE_LUT_MAX_YEAR]`, exactly like `makeDateTime`
already does since the `DateTime64` extension. That single change covers
text parsing everywhere: SQL casts from `String`, CSV/JSON/TSV/`Values`
input formats, and `YYYYMMDDToDayNum`. Computations over the extended
values were already handled by the `DateTime64` infrastructure, which
gates every `ExtendedDayNum` argument with an out-of-range escape path.
`Date` behavior is unchanged: its clamps happen downstream, on the
day-number result.

The LUT-derived `DATE_LUT_MAX_EXTEND_DAY_NUM` (120530, an exclusive
bound) is replaced by inclusive `DATE_LUT_MIN_EXTEND_DAY_NUM` (-719528,
`0000-01-01`) and `DATE_LUT_MAX_EXTEND_DAY_NUM` (2932896, `9999-12-31`),
tied to the internal representable window by static asserts.

In the numeric conversion `toDate32(N)`, the day-number/timestamp
disambiguation threshold moves accordingly: values up to 2932896 are day
numbers, larger values are Unix timestamps capped at the new
`MAX_DATE32_TIMESTAMP` (`9999-12-31 23:59:59` instead of `2299-12-31
23:59:59`); values below the minimum saturate to `0000-01-01` instead of
`1900-01-01`. The monotonicity analysis threshold is kept in sync, and
the Parquet, Arrow, Arrow IPC and native ORC readers validate `Date32`
input against the new bounds (also fixing an off-by-one that accepted
day number 120530). `makeDate32`, `YYYYMMDDToDate32` and `changeDate`
accept years `[0, 9999]`. The default value of `Date32` and the result
of `toDate32OrZero` on unparseable input remain `1900-01-01`.

Closes #111524

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@clickhouse-gh

clickhouse-gh Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Workflow [PR], commit [549f6a7]

Summary:


AI Review

Summary

This PR extends Date32 to the full 0000-01-01 .. 9999-12-31 window and, after the follow-up fixes in the branch, the touched parsing, conversion, import-format, and generated-doc paths now look internally consistent. The remaining blocker is the intentionally widened numeric interpretation cutoff in toDate32(number): it changes existing query results across upgrade, but the PR still provides no compatibility-level escape hatch to keep the old semantics during rollout.

Findings

❌ Blockers

  • [dismissed by author -- https://github.com/Extend the supported range of Date32 to [0000-01-01, 9999-12-31] #111534#discussion_r3650789186] [src/Functions/FunctionsConversion.h:404] widens the numeric day-number branch from the old Date32 ceiling to DATE_LUT_MAX_EXTEND_DAY_NUM, so every existing toDate32(number) call in [120530, 2932896] changes meaning after upgrade. That is a real backward-incompatible semantic change, and this code still has no compatibility-controlled path to preserve the pre-PR interpretation for clusters that need a staged rollout. Suggested fix: gate the old/new cutoff behind a compatibility setting (with the old threshold for older compatibility levels) and record that switch in the compatibility history.
Final Verdict

Changes are close, but the backward-incompatible toDate32(number) reinterpretation still needs a compatibility-mode migration path before this is safe to merge under the repo's compatibility policy.

LLVM Coverage Report

Metric Baseline Current Δ
Lines 86.70% 86.70% +0.00%
Functions 92.00% 92.00% +0.00%
Branches 79.00% 79.00% +0.00%

Changed lines: Changed C/C++ lines covered: 410/433 (94.69%) · Uncovered code

Full report · Diff report

@clickhouse-gh clickhouse-gh Bot added the pr-backward-incompatible Pull request with backwards incompatible changes label Jul 23, 2026
@mintlify

mintlify Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
ClickHouse-docs 🟢 Ready View Preview Jul 23, 2026, 7:47 AM

@yariks5s yariks5s self-assigned this Jul 23, 2026
Comment thread tests/queries/0_stateless/04626_extend_date32_range.sql
@mintlify

mintlify Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
ClickHouse-docs 🟡 Building Jul 23, 2026, 7:24 AM

alexey-milovidov and others added 8 commits July 24, 2026 01:21
On Darwin, `time_t` is `long` while `DateLUTImpl::Time` is `Int64` (`long long`) - distinct
types - so `may_be_out_of_lut_range` was false for the `time_t` arguments that
`ToDate32TransformFromSecondsOrDays` passed to `toDayNum`, the cctz escape path was compiled
out, and timestamps beyond the LUT end saturated to `2299-12-31` instead of `9999-12-31`.
Pass `DateLUTImpl::Time` instead.

Fixes the `Fast test (arm_darwin)` failures in 04626_extend_date32_range, 02477_age_date32,
03212_variant_dynamic_cast_or_default and 03604_to_date_casts:
https://s3.amazonaws.com/clickhouse-test-reports/json.html?PR=111534&sha=cb0accdedb4b3cfdb9373d1f34f18df23add0c02&name_0=PR&name_1=Fast%20test%20%28arm_darwin%29
#111534

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`toDate32('2999-12-31')` and `toDate32('1000-12-31')` no longer clamp to the old
`[1900-01-01, 2299-12-31]` boundaries - both dates are now within the supported range.

#111534

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ToYearImpl::getPreimage and ToYYYYMMImpl::getPreimage still refused years outside
1900..2299, so predicates like toYear(d) = 1500 on a table ordered by d lost primary key
pruning over the newly valid Date32 range. Widen the check to
DATE_LUT_MAX_REPRESENTABLE_YEAR. The year 9999 (and month 9999-12) stays excluded
because the exclusive upper endpoint of its preimage would be the first moment of the
next year/month, which is not representable.

Addresses the AI review on #111534

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The reference file for `04641_date32_extended_range_preimage` was committed empty.
Generated the output: `toYear`/`toYYYYMM` predicates over the extended `Date32`
range are rewritten to raw key ranges, and the year 9999 boundary stays unrewritten
but returns the correct result.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@alexey-milovidov

Copy link
Copy Markdown
Member Author

The Upgrade check failure (allow_experimental_text_index_positions reported as UNKNOWN_SETTING on attach after downgrade) is unrelated to this PR; the fix is in progress in #110865.

The Fast test (arm_darwin) failures and test_timezone_config::test_overflow_toDate32 are addressed by the pushed commits: on Darwin time_t is long while DateLUTImpl::Time is Int64 (long long), so the out-of-LUT-range escape path in toDayNum was compiled out and timestamps beyond 2299 saturated to the LUT end instead of 9999-12-31.

Comment thread src/Functions/FunctionsConversion.h
Comment thread src/Functions/FunctionsConversion_reg.cpp Outdated
@alexey-milovidov

Copy link
Copy Markdown
Member Author

Update (c8fd3d4bc49):

  • Merged the latest master (the branch was 269 commits behind) and rebuilt; the local Date32 tests 04626_date32_extended_range and 04641_date32_extended_range_preimage pass.
  • Addressed the AI review Major: the generated docs for toDate32OrZero no longer call 1900-01-01 the lower boundary of Date32; it is now described as the historical default value returned for invalid input, with the actual lower boundary (0000-01-01) spelled out.
  • The AI review Blocker (the widened numeric cutoff of toDate32(N)) is intentional and is not going to be gated behind a compatibility setting: the change follows the rule that a number that fits into the day-number range is a day number, the pull request is filed under the Backward Incompatible Change category, and the affected numeric range is spelled out in the changelog entry.
  • The only remaining red is CH Inc sync ("tests failed"): 03212_variant_dynamic_cast_or_default timed out ("Test runs too long") in the private-only Stateless tests (amd_asan_ubsan, flaky check, s3 storage, meta in keeper) job. This pull request changes only that test's .reference file, which is why the flaky check runs it repeatedly; all four public flaky-check configurations are green. The sync run is re-triggered by this push.

@alexey-milovidov

Copy link
Copy Markdown
Member Author

Update (6e5b9a2e024): merged the latest master (the branch was 186 commits behind), rebuilt (ninja clickhouse, ok), and re-ran the two Date32 tests locally — 04626_extend_date32_range and 04641_date32_extended_range_preimage both pass.

Status of the reds on the previous commit c8fd3d4bc49:

The AI Review blocker (the widened numeric cutoff of toDate32(N)) stays dismissed on purpose: a number that fits into the day-number range is treated as a day number, the pull request is filed under Backward Incompatible Change, and the affected numeric range is spelled out in the changelog entry.

@groeneai, please investigate the 04327_runtime_filter_nested_variant flakiness (https://s3.amazonaws.com/clickhouse-test-reports/json.html?PR=111534&sha=c8fd3d4bc49eec86ce71439935063deda8927521&name_0=PR&name_1=Stateless%20tests%20%28amd_asan_ubsan%2C%20distributed%20plan%2C%20parallel%29) and provide a fix in a separate pull request; there is no tracking issue for it yet. If a fix is already in progress, please link it here.

@groeneai

Copy link
Copy Markdown
Collaborator

A fix is already in progress, and it is your own #111691 ("Pin join_runtime_filter_min_probe_rows in tests that assert runtime filter effects"), still open. It pins join_runtime_filter_min_probe_rows = 0 in 04327_runtime_filter_nested_variant.sql among 12 runtime filter tests, so I am not opening a duplicate pull request, and no tracking issue is needed since that pull request lands the fix.

Mechanism, for the record. The failing assertions in this test are plan shape ones of the form

SELECT count() > 0 FROM (EXPLAIN actions = 1 ... ) WHERE explain ILIKE '%BuildRuntimeFilter%';

which is why the diff is -1 +0 and not a data mismatch. tryBuildRuntimeFilter bails out early on a small probe side (src/Processors/QueryPlan/Optimizations/joinRuntimeFilter.cpp:249-256):

    if (optimization_settings.join_runtime_filter_min_probe_rows > 0)
    {
        auto probe_size = join_step->getInputRowsEstimation(JoinTableSide::Left);
        if (probe_size && *probe_size <= optimization_settings.join_runtime_filter_min_probe_rows)
            return false;
    }

Two settings the test runner randomizes have to line up for that return false to fire:

  • join_runtime_filter_min_probe_rows (tests/clickhouse-test:1566, drawn as 0 with probability 0.1, otherwise randint(1, 10000); the declared default is 1000), and
  • query_plan_optimize_join_order_randomize (tests/clickhouse-test:1556), which makes optimizeJoin replace real relation statistics with getRandomizedStats (src/Processors/QueryPlan/Optimizations/optimizeJoin.cpp:792-793). Those statistics reach JoinStepLogical::setOptimized, become left_rows_estimation, and are exactly what getInputRowsEstimation(JoinTableSide::Left) returns above.

So the probe side estimate becomes a random number, and when it lands at or below the randomized threshold the runtime filter is not built and the EXPLAIN assertion flips to 0. The minimizer in your own failing run already isolated both of them:

Culprit settings: --query_plan_optimize_join_order_randomize 428027 --join_runtime_filter_min_probe_rows 8842
Step 1 (same randomized settings): Runs: 13, Failed: 13
Step 2 (no randomization):         Runs: 15, Failed: 0, Passed: 15

8842 against a randomized estimate, rather than the default 1000 against a real one.

Why #111691 closes it completely: the guard is wrapped in if (join_runtime_filter_min_probe_rows > 0), so pinning the setting to 0 makes the whole skip unreachable by construction, whatever the randomized estimate happens to be. Corroborating that structurally, with only #111691's pin applied to this test and nothing else changed, an 18 seed sweep of query_plan_optimize_join_order_randomize (including 951826, 610415 and 6) passed 18 out of 18.

One correction to something I want to avoid leaving on the record: this is not a join side swap. The statements already carry a per query query_plan_join_swap_table = false, which is precisely why that explanation does not hold, and it does not stop the failure.

Your observation that it is unrelated to Date32 matches CIDB: over the last ten days I see failures on #110078 (twice), #111534, #111847, #110886 and #111721, and zero on master, which is the expected profile for a PR only settings randomization flake.

Comment thread src/Common/DateLUTImpl.h
# Conflicts:
#	src/Functions/FunctionsConversion_reg.cpp
…UT dates

The review asked `isMakeDateOutOfRange` to reject calendar-invalid dates such as
`1899-02-30` before taking the `cctz` escape path. That would make years outside
`[1900, 2299]` stricter than years inside it: the lookup table has always normalized
an overlong day of month, so `makeDate32(1999, 2, 30)` is `1999-03-02` and
`makeDate32(1984, 2, 30)` is `1984-03-01` (pinned in `02243_make_date32` long before
this change). Rejecting the same input only for pre-1900 and post-2299 years would
mean the same expression has a different meaning depending on the year.

Add `04651_date32_out_of_lut_calendar_normalization` which checks, for `toDate32`,
`makeDate32` and `YYYYMMDDToDate32`, that February 30 and April 31 normalize
identically inside and outside the lookup table window, and that truly malformed
components (month or day outside `1..12` / `1..31`) still take the error path
everywhere.
@alexey-milovidov

Copy link
Copy Markdown
Member Author

🕵 Status update: CI on 3d420628798a was fully green, so I did not merge master (429 behind, but less than a day old at the merge base and a merge would only reset a green run).

Fixed the remaining AI-review blocker in 6dfd4596a33b: a Date32 day whose midnight is not representable at the target DateTime64 scale was clamped unconditionally, so 9999-12-31 read into DateTime64(9) came back as the saturated maximum even under date_time_overflow_behavior = 'throw'. ToDateTime64Transform now honors the setting, FunctionCast::createDecimalWrapper dispatches on it for the Date32 -> DateTime64 branch (it previously always used the default mode), and the ORC, Avro, Parquet, Arrow, ArrowStream and Arrow IPC date readers validate the day number against the window of the requested scale instead of the full Date32 range, since their cast is context-less. Regression test 04838_date32_to_datetime64_scale_overflow covers all five format readers plus the CAST at scale 9, as the review asked.

The other unresolved thread is the compatibility-setting request, which stays dismissed — the Backward Incompatible Change category and the changelog entry already spell out the reinterpretation of numeric inputs in [120530, 2932896].

Comment thread src/Processors/Formats/Impl/ArrowColumnToCHColumn.cpp
Comment thread src/Processors/Formats/Impl/NativeORCBlockInputFormat.cpp
alexey-milovidov and others added 3 commits August 11, 2026 04:21
…eference was truncated after the first Parquet block

The test outputs 47 lines (a CAST section plus five format blocks), but only the
first 13 lines were committed, so the test failed with "result differs with
reference" in every stateless configuration.

https://s3.amazonaws.com/clickhouse-test-reports/json.html?PR=111534&sha=6dfd4596a33b2490827d34ee3788805fdf5dc2ae&name_0=PR

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…he date range checks of the Arrow and ORC readers

The Arrow and native ORC readers dispatch their `DATE`-column handling on the
requested header type, but the hint arrived unstripped, so a
`LowCardinality(Date)` or `LowCardinality(DateTime)` target skipped the new
range-check branches: Arrow fell back to the plain `Date32` path (the later
context-less cast then clamped or wrapped with the default overflow mode
instead of honoring `date_time_overflow_behavior`), and ORC fell clear through
to the raw `Int32` branch, so even an in-range day count was cast as unix
seconds instead of midnight of that day. Strip `LowCardinality` and `Nullable`
from the hint first, the same way `readColumnWithTimestampData` and the Arrow
IPC `stripHint` already do. The Parquet and Avro readers already strip or
recurse into the wrapper.

`LowCardinality(DateTime64(...))` from the review example turned out to be not
constructible (`DataTypeLowCardinality` only accepts numbers, strings, `Date`
and `DateTime`), so `Date` and `DateTime` cover all reachable wrapped targets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@alexey-milovidov

Copy link
Copy Markdown
Member Author

🕵 Merged master and pushed 36d641a45ae6.

CI red on 6dfd4596a33b — the only failing test was this PR's own 04838_date32_to_datetime64_scale_overflow, red in 9 stateless configurations because its committed .reference was truncated after the first Parquet block (13 of 47 lines). Regenerated it from the built binary (report).

Both AI-Review blockers on the LowCardinality wrapper gap are fixed — the Arrow and native ORC readers now strip LowCardinality/Nullable from the requested type before dispatching the DATE column handling, with the new regression test 04844_orc_arrow_lowcardinality_date_targets covering Parquet/Arrow/ArrowStream/ORC/Avro. See the thread replies for details; notably LowCardinality(DateTime64(...)) is not a constructible type, so Date/DateTime cover all reachable wrapped targets. The remaining blocker (a compatibility setting for the widened numeric toDate32(N) cutoff) stays dismissed on-thread.

All touched format tests (04658, 04670, 04759, 04761, 04836, 04838, 04844) pass locally.

The embedded documentation of `toDate32` and `toDate32OrZero` in
`src/Functions/FunctionsConversion_reg.cpp` was updated for the extended
range, but the published copy in
`docs/reference/functions/regular-functions/type-conversion-functions.mdx`
was still the stale autogenerated text: it described `1900-01-01` as the
lower boundary of `Date32` and showed `toDate32('1899-01-01')` saturating
to `1900-01-01`.

Also fixed the same claim in the source documentation of
`toDate32OrDefault` (`src/Functions/castOrDefault.cpp`): its default value
is `1900-01-01`, which is the historical default of the type, not its lower
boundary, which is now `0000-01-01`.
`master` added `04838_in_subquery_lowcardinality_result_type` and
`04844_type_evolution_matrix_widen`, which clash with the numbers used by
this branch. Renumbered `04838_date32_to_datetime64_scale_overflow` to
`04848_...` and `04844_orc_arrow_lowcardinality_date_targets` to
`04849_...` (the temporary file names inside the tests too).
@alexey-milovidov

Copy link
Copy Markdown
Member Author

🕵 Merged master (272 behind) and pushed 549f6a7a2f89.

Addressed the AI-Review Major (stale generated docs). The embedded documentation of toDate32 / toDate32OrZero was updated for the extended range, but the published autogenerated copy in docs/reference/functions/regular-functions/type-conversion-functions.mdx was still the old text — it described 1900-01-01 as the lower boundary of Date32 and showed toDate32('1899-01-01') saturating to 1900-01-01. Both are refreshed now. While there, toDate32OrDefault made the same claim, and since DataTypeDate32::getDefault still returns 1900-01-01 while the lower boundary is now 0000-01-01, that claim became wrong too — fixed in the source (src/Functions/castOrDefault.cpp) and in the generated copy. See the thread reply.

Test renumbering. master added 04838_in_subquery_lowcardinality_result_type and 04844_type_evolution_matrix_widen, which collided with this branch's numbers, so 04838_date32_to_datetime64_scale_overflow became 04848_… and 04844_orc_arrow_lowcardinality_date_targets became 04849_….

All 18 touched tests pass locally against a fresh build.

Both reds on 36d641a45ae6 are unrelated:

@groeneai, please investigate the AST fuzzer whole-job timeout: https://github.com/ClickHouse/ClickHouse/actions/runs/31459111999/job/93712866959 — the server cannot be stopped while such a query is stuck, so the job burns its full 5-hour budget instead of reporting a hung query. A fix in a separate PR would be appreciated; if one is already in progress, please link it here.

@groeneai

Copy link
Copy Markdown
Collaborator

The harness half is already in flight: #111934, "AST fuzzer: bound post-fuzz stages and detect a memory-stuck server". It bounds the teardown wait you hit, plus the client reap and the liveness-probe window on the same path.

One refinement from re-reading the job log: clickhouse stop is itself bounded (60 s TERM, 10 s TERM again, 100 s of SIGKILL checks, programs/install/Install.cpp:1204-1240), and none of its output ("Sent terminate signal", "Waiting for server to stop") appears in the log at all. The unbounded wait is wait $server_bg_pid at ci/jobs/scripts/fuzzer/run-fuzzer.sh:423: the script waits on the server subshell, not on stop_server, so a server that never exits blocks it regardless. The last shell trace is + stop_server at 08:27:38; after that only gdb New Thread lines until the runner's Timeout exceeded [18000] at 12:55:54. 4 h 28 min, 89% of the job, in one statement.

The expensive part is that status.tsv is written at :426, after that wait, so the job uploaded no status.tsv, no server.log, no fuzzer.log. Only job.log survives, and the result is a bare praktika ERROR whose info is a gdb thread dump. The query history that would attribute the stall is destroyed.

#111934 replaces the wait with a 180 s poll, then SIGKILLs and writes a teardown watchdog marker, so the run reports the stall with its logs attached in about 33 min instead of being cancelled at 5 h. It does not make the query interruptible: yours is the merge(REGEXP('^system$'), 't.*') shape from #112203, and a harness bound is a diagnosability fix, not a fix for the stall.

It is open and unreviewed since 2026-08-05. If you would prefer the teardown bound alone, split from the memory-stuck detection it carries, I will do that.

@alexey-milovidov
alexey-milovidov added this pull request to the merge queue Aug 12, 2026
Merged via the queue into master with commit e05959c Aug 12, 2026
181 checks passed
@alexey-milovidov
alexey-milovidov deleted the extend-date32-range branch August 12, 2026 15:16
@robot-ch-test-poll3 robot-ch-test-poll3 added the pr-synced-to-cloud The PR is synced to the cloud repo label Aug 12, 2026
alexey-milovidov pushed a commit that referenced this pull request Aug 12, 2026
…s-out-of-column-type-range

Conflict in `src/Interpreters/convertFieldToType.cpp`: both sides range-check an
exact integer `Field` converted to a `Date32` target and cover both integer
carriers. Master's version (from
#111534) is the stronger one - it
rejects day numbers outside the representable calendar
`[DATE_LUT_MIN_EXTEND_DAY_NUM, DATE_LUT_MAX_EXTEND_DAY_NUM]` =
`[0000-01-01, 9999-12-31]`, a strict subset of the `Int32` storage range this
branch checked - so keep it and drop this branch's variant. The `WITH FILL`
bound checks in `FillingTransform` only need `convertFieldToType` to return Null
for a value the column type cannot hold, which the kept version still does.
alexey-milovidov pushed a commit that referenced this pull request Aug 12, 2026
…acros from master

Master now defines these two macros as the day numbers of `0000-01-01` and
`9999-12-31` (#111534), with
static assertions tying them to `min_representable_day_index` and
`max_representable_day_index` - exactly the expressions the accessors added on
this branch returned. Drop the accessors, use the macros the rest of the
codebase already uses, and note in `FillingTransform` that
`convertFieldToType` now rejects out-of-calendar `Date32` day numbers too, while
the window is still needed here for the dedicated `INTERVAL`-step message and
for `DateTime64`.
alexey-milovidov pushed a commit that referenced this pull request Aug 12, 2026
…erge

The `Date32` range extension on master
(#111534) made
`toDate32('9995-06-01')` parse to the actual date instead of clamping to
`2299-12-31`, so the anchor of

    SELECT count() > 0 FROM (SELECT toDate32('9995-06-01') AS d
        ORDER BY d ASC WITH FILL TO 2932896 STEP INTERVAL 1 YEAR)

now sits four steps below the calendar boundary and its sequence steps *over*
`TO` = `9999-12-31` instead of onto it: `9999-06-01` + 1 year would leave the
representable calendar, so the `INTERVAL` step returns its input unchanged and
the filling stagnates strictly below `TO` forever. That is the data-dependent
shape the pull request lists as not fixed - without a `FROM`, the anchor, and
hence the stagnation, is only known at execution time - so it is the test query
that has to be picked so that it terminates.

Use an anchor whose sequence lands exactly on the boundary
(`toDate32('9995-12-31')`), which keeps what the query asserts: a `TO` at
exactly the calendar boundary is accepted and reachable. The output is
unchanged, so the reference file stays as is.
alexey-milovidov pushed a commit that referenced this pull request Aug 12, 2026
…by master

Master's `NumericToDate32` suite (from
#111534) already covers exactly
what the `Date32` assertions added here did - both integer carriers, the exact
boundaries, and a value that does not fit the underlying `Int32` - and does so
against the narrower representable calendar rather than the storage range. Keep
only the `Date` and `DateTime` assertions, which nothing else covers, and add
the `Int64` carrier for `DateTime`: the branch this pull request changes accepts
it, while the previous code handled `UInt64` alone.
groeneai added a commit to groeneai/ClickHouse that referenced this pull request Aug 13, 2026
Master extended Date32 to [0000-01-01, 9999-12-31] in ClickHouse#111534, which touches the same
transforms and field-coercion helpers this PR rewrites.

Conflict resolution:
- ToDate32TransformFromSecondsOrDays: take master's DATE_LUT_MIN_EXTEND_DAY_NUM lower bound
  (daynum_min_offset no longer exists) and keep this PR's formatOutOfBoundsValue helper on the
  throw path. Master's separate is_nan check is dropped as redundant: the isFinite early throw
  above it already rejects NaN and inf for every mode.
- convertFieldToType: keep this PR's overflow-aware coercion helpers, which subsume master's
  inline Date32 range check, and retarget their bounds to the extended range.
- toDate32 documentation: state the new range alongside the setting-dependent behaviour.

Two defects the moved bounds exposed, both fixed here:
- DATE32_MAX_TIMESTAMP_FIELD still mirrored the old 2299-12-31 timestamp, so the field path
  saturated three centuries below CAST.
- The day-number/timestamp predicate in the Date32 field helper was non-strict while the
  transform's is strict, so the boundary day number 2932896 materialized as 1970-02-03 through
  INSERT ... VALUES while CAST returned 9999-12-31. Both now use the strict form.

The fractional-boundary test carriers were chosen against the old boundary (120530) and no
longer straddle it, so they were retargeted to 2932896 and an integer arm was added for the
boundary day number itself. Verified that arm fails against a binary without the predicate fix.

Submodule working trees were resynced to the merged pins (six had stale checkouts, which broke
the build on NuRaft's entry_at_ext).
alexey-milovidov added a commit to nihalzp/ClickHouse that referenced this pull request Aug 14, 2026
…e_binary`

The Apache Arrow library reader for the `Arrow` formats was removed in ClickHouse#111996,
so `input_format_arrow_use_native_reader` is an obsolete no-op and the two loops
over both readers now ran the same reader twice. Each file is read once, and the
notes about what the library reader could not read are gone: unions and NULL
list/map slots spanning a non-empty range are no longer special.

`04512` also moves its out-of-range day number to the end of the `Date32` range
that ClickHouse#111534 extended, since `2299-12-31 + 100` is a valid date now.

`04513` gains the `fixed_size_binary` leaves the ClickHouse writer uses for
`UUID`, `IPv6` and the 128/256-bit integers, including the self-describing Arrow
`uuid` extension type, which the review asked for. These are crafted inline with
`pyarrow` (as `04613` does) instead of shipping three more binary fixtures - the
layout is easier to review as code, and it doubles as documentation of how the
committed fixtures were made.
yisamlee added a commit to yisamlee/ClickHouse that referenced this pull request Sep 11, 2026
DateTime64 (PR ClickHouse#107907, 26.7.1) and Date32 (PR ClickHouse#111534, 26.7.4)
independently extended their supported range from
[1900-01-01, 2299-12-31] to [0000-01-01, 9999-12-31], but the docs
only ever showed the new range. A customer hit this gap: querying
toDateTime64('1899-01-01', 9) on an older version returns a
silently-clamped 1900-01-01 with no indication anything was cut off.

Add a "Before version X" note to both types' embedded doc source
(and the generated .mdx mirrors, since autogenerate_docs.py needs a
built binary to regenerate them) so the old behavior is discoverable.
Date and DateTime (32-bit) are unaffected -- their ranges are fixed
by storage width, not by the date-lookup-table extension -- so left
unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-autogenerated-docs PR that regenerates docs artifacts from source; exempt from the autogenerated-region edit guard pr-backward-incompatible Pull request with backwards incompatible changes pr-synced-to-cloud The PR is synced to the cloud repo

Projects

None yet

4 participants