1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
//! chtypes — ClickHouse's own type system, per ClickHouse version, from Rust.
//!
//! chtypes answers one question, exactly: **if this row were inserted into this
//! ClickHouse table on this ClickHouse version, what would happen?** It answers
//! it by running ClickHouse's own C++ machinery — `DataTypeFactory`,
//! `ISerialization`, `ReadHelpers`, `evaluateMissingDefaults`, the TTL
//! algorithms, `MergeTreeDataWriter::mergeBlock` — vendored per release and
//! linked behind the frozen `chs_*` C ABI. Nothing here reimplements a coercion
//! rule, which is why the answers are exact by construction.
//!
//! This crate is a peer SDK over that ABI, alongside Go, Python and TypeScript.
//! The language-neutral contract is `spec/` in this repository; where this crate
//! and `spec/` disagree, the spec wins and this is a bug.
//!
//! ```no_run
//! use chtypes::{Format, Registry, NO_SETTINGS};
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let registry = Registry::from_env_or_default()?; // $CHTYPES_REGISTRY, else the per-user cache
//! let lib = registry.for_version("25.8")?; // minor line or exact patch
//! let schema = lib.compile("ts DateTime, seq UInt8").compile()?;
//!
//! let batch = schema.rows(
//! Format::JsonEachRow,
//! br#"{"ts":"2026-01-15 10:30:00","seq":256}"#,
//! NO_SETTINGS,
//! )?;
//!
//! println!("{} {:?}", batch.outcome, batch.rows[0].values);
//! for t in &batch.transformed {
//! // seq: 256 -> 0, overflow_wrap, lossy — and ClickHouse returned success.
//! println!("row {} {}: {} -> {} ({})", t.row, t.column, t.input, t.stored, t.reason);
//! }
//! # Ok(()) }
//! ```
//!
//! # What this crate will not do
//!
//! * **Never map [`Error::Unsupported`] onto a rejection or an acceptance.**
//! `-2` ([`CODE_UNSUPPORTED`]) means "a real server might well have accepted
//! this; I decline to guess". Mapping it to a rejection manufactures an
//! over-reject; mapping it to an acceptance manufactures an over-accept, which
//! is the cardinal sin — rows stream to subscribers and then the insert fails.
//! * **Never infer one version's answer from another's.** Behaviour is not
//! monotonic: 25.10 rejects a mixed-type DEFAULT that 24.8 through 25.8 and
//! 26.6 onward all accept; `JSON` is rejected on 24.8 and accepted from 25.3.
//! [`Registry::for_version`] fails, naming what is loaded, rather than
//! answering from the nearest artifact.
//! * **Never treat a per-row `accepted` as "stored".** A TTL-expired row is
//! accepted per row and not stored per batch. [`BatchResult::transformed`]
//! folds in the batch-level `storage_transforms`, and
//! [`BatchResult::engine_rows`] — when present — is the stored truth, not
//! [`BatchResult::rows`].
//! * **Never route a value through a float.** Settings values cross as strings
//! and stored values stay raw JSON text; `18446744073709551615` must not
//! become `18446744073709552000`.
//! * **Never decode a stored value into a language type before comparing it.**
//! A ClickHouse `String` holds arbitrary bytes, so a stored rendering is
//! [`RawText`] — bytes, with a *fallible* UTF-8 view — and never a `String`
//! that silently carries U+FFFD where the value had bytes. See [`Value::text`].
//!
//! # Getting artifacts
//!
//! An artifact is one ClickHouse release compiled behind the C ABI — 166–302 MB
//! each, hours of C++ compute. Fetch prebuilt, signed ones with the crate's own
//! command (`cargo install chtypes` → `chtypes fetch 25.8`) or from Rust with
//! [`ensure`] — the `docs/fetch.md` contract, behind the default-on `fetch`
//! feature; `scripts/fetch.sh` is the reference implementation of the same
//! chain. A local build lands in the same per-user cache
//! (`~/.cache/chtypes/artifacts/<os>-<arch>`). [`Registry::from_search_path`]
//! looks there, in `$CHTYPES_REGISTRY` and in the system locations, and names
//! every place it looked when a line is missing ([`Error::ArtifactMissing`]);
//! [`Registry::new`] loads one explicit directory.
//!
//! # Platform
//!
//! Unix only — the loader is `dlopen`. Linux is the shipping target; macOS is a
//! development floor and **not** an oracle: its `long double` is 53-bit, so float
//! parses diverge from a real server (the float corpus matches 395/395 on Linux
//! and 0/395 on macOS). Any float expectation must come from a Linux artifact or
//! a live server.
compile_error!;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use RawText;
pub use ;
pub use ;
pub use ;
pub use reason;