Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
5ec74b9
v2 spec: spec batch 2, ABI v2 fingerprint d5323993…41c2
EricAndrechek Oct 19, 2026
4740cd5
go (spec batch 2): the options documents, the b64 value form, the new…
EricAndrechek Oct 19, 2026
b787100
go (spec batch 2): the decoders for the refusal, export and schema me…
EricAndrechek Oct 19, 2026
01e958f
go (spec batch 2): the stub goldens document states the documents' co…
EricAndrechek Oct 19, 2026
f5ab978
go (spec batch 2): bindings-v1.md rows and the parity allowlist for t…
EricAndrechek Oct 19, 2026
7e91416
go (spec batch 2): CHANGELOG
EricAndrechek Oct 19, 2026
1e94950
v2 generator: call errors carry chs_error_reason as a reason field
EricAndrechek Oct 19, 2026
79db1a7
stubtest: call the v2 signatures of preview_row, filter_create and fi…
EricAndrechek Oct 19, 2026
9ee594d
Merge v2-spec-batch-2 (call errors carry reason; stubtest)
EricAndrechek Oct 19, 2026
628eedc
go: CallError.Reason from the generated reason field
EricAndrechek Oct 19, 2026
d473294
docs: bindings-v1.md tables realigned (dprint fmt)
EricAndrechek Oct 19, 2026
7bb745f
python: spec batch 2 hand-written surface (options, b64 values, refus…
EricAndrechek Oct 19, 2026
9e29533
rust: spec batch 2 hand-written surface (options documents, refusal a…
EricAndrechek Oct 19, 2026
1279296
ts: spec batch 2 port (options documents, b64 values, refusal members…
EricAndrechek Oct 19, 2026
751b2a1
python: spec batch 2 docs, CHANGELOG, parity allowlist entries, reaso…
EricAndrechek Oct 19, 2026
972c97e
rust: goldens runner passes the new options and columns arguments
EricAndrechek Oct 19, 2026
0b58539
examples(ts): follow the spec batch 2 surface (nullable spans, no row…
EricAndrechek Oct 19, 2026
eb1ffdf
rust: stub goldens fixture follows the row document (code, no row uns…
EricAndrechek Oct 19, 2026
18c2a3b
ts(test): at_merge expectations keep the partRow mapping under the ro…
EricAndrechek Oct 19, 2026
2755452
Merge origin/v2-sb2-py into v2-sb2-int
EricAndrechek Oct 19, 2026
9c5ac78
Merge origin/v2-sb2-ts into v2-sb2-int
EricAndrechek Oct 19, 2026
1df7666
Merge origin/v2-sb2-rs into v2-sb2-int
EricAndrechek Oct 19, 2026
40fc470
Merge origin/v2 into v2-sb2-int
EricAndrechek Oct 19, 2026
72c16e7
abi: the generator emits CODE_DECLINED for Python, TypeScript and Rust
EricAndrechek Oct 19, 2026
14dd039
parity-surface: read the description of the major the bindings speak
EricAndrechek Oct 19, 2026
d7630b8
docs: settings.md describes the b64 form for a non-UTF-8 value
EricAndrechek Oct 19, 2026
64a27e0
Merge origin/v2 (7c04fb0c) into v2-sb2-int
EricAndrechek Oct 19, 2026
6892d4d
ts test: the fetch-code census skips the numeric CODE_DECLINED
EricAndrechek Oct 19, 2026
8e17e31
Merge origin/v2 into v2-sb2-int (the RustSec lockfile bumps)
EricAndrechek Oct 19, 2026
bb81cdc
Merge origin/v2 into v2-sb2-int (2.0.0-dev.10 versions)
EricAndrechek Oct 19, 2026
1b2a532
test+docs: column_defaults wire form and default_override decode, in …
EricAndrechek Oct 20, 2026
2ce065c
examples(go,python,rust): follow the spec batch 2 surface (no row-lev…
EricAndrechek Oct 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions docs/guides/batches.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,57 @@ Three payload states, and they are distinct: absent means no export was requeste

Attaching a compiled filter to this same call narrows the export further, to the rows the filter admits, from the same one parse: [`filters.md` → Exporting only the rows a filter admits](filters.md#exporting-only-the-rows-a-filter-admits).

## Overriding a column's DEFAULT for one call (ABI v2)

`column_defaults` is a per-call list of `{name, value}`. In a cell the server would have filled from the column's DEFAULT, the call uses your `value` instead. The library decides which cells those are, by ClickHouse's own reader and the call's format settings: a field the record omits, a `null` for a non-Nullable column under `input_format_null_as_default`, an empty CSV field under `input_format_csv_empty_as_default`. A field the record supplied is never overridden, and `""` is a value like any other. A cell an override fills reads `default_override` (`Source` in each binding), which is stored, and the export carries it as a present value, so inserting the export needs no override.

The binding only passes the list: `name` and `value` are byte strings (UTF-8, else the `name_b64` and `value_b64` forms), the order is kept, and an empty list is sent as `[]`. It validates nothing. An entry that names an unknown, non-insertable, MATERIALIZED or ALIAS column, or a value that does not read as the column's type, is `CHS_INVALID_ARGUMENT` at the call, naming `column_defaults[i]`. A build that does not implement the member declines it. The option exists on the four calls that model an INSERT of a body: row, rows, parse a block and filter rows.

<details open><summary><b>Go</b></summary>

```go
batch, err := schema.Rows(chtypes.JSONEachRow, body,
chtypes.WithColumnDefaults([]chtypes.ColumnDefault{{Name: "region", Value: "eu"}}))
// a cell filled from the override: batch.Rows[i].Columns[j].Source == chtypes.SourceDefaultOverride
```

</details>

<details><summary><b>Python</b></summary>

```python
batch = schema.rows(
Format.JSON_EACH_ROW, body, column_defaults=[ColumnDefault("region", "eu")]
)
# a cell filled from the override has source == Source.DEFAULT_OVERRIDE
```

</details>

<details><summary><b>TypeScript</b></summary>

```ts
const batch = schema.rows(Format.JSONEachRow, body, {
columnDefaults: [{ name: 'region', value: 'eu' }],
});
// a cell filled from the override has source Source.DefaultOverride
```

</details>

<details><summary><b>Rust</b></summary>

```rust
let options = RowsOptions {
column_defaults: Some(vec![ColumnDefault { name: b"region".to_vec(), value: b"eu".to_vec() }]),
..Default::default()
};
let batch = schema.rows(Format::JsonEachRow, body, &options)?;
// a cell filled from the override has source Source::DefaultOverride
```

</details>

## Next

- [`transformations.md`](transformations.md) — what the accepted rows were silently changed into.
Expand Down
11 changes: 10 additions & 1 deletion docs/guides/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,16 @@ This has cost real bugs, so v1 makes it one rule in all four bindings: **a setti

The reason is one setting in particular. `chtypes_now_epoch_nanos` is a 19-digit nanosecond epoch, and 19 digits do not survive an IEEE double: `1700000000123456789` becomes `1.7e+18`. Sent as a JSON number, the setting would be **silently ignored** — the batch keeps stamping the real wall clock, and nothing anywhere says so. A loud `TypeError` is the whole point.

A value whose bytes are not valid UTF-8 cannot be passed as a setting or a query parameter in 1.0. Inline it in the SQL as `unhex('<hex>')`, built from hex digits only ([`limitations.md`](../limitations.md#binary-input-parameters-must-be-utf-8)).
A value whose bytes are not valid UTF-8 is sent in the object form `{"b64": "<standard base64, padded>"}` (ABI v2): a setting value, a query-parameter value, a `Setup` default and a value of a server profile's `settings`. The binding writes it in place of the string, so the library sees the exact bytes; a value that is valid UTF-8 stays a plain string. Three of the bindings can send one:

| Binding | How a non-UTF-8 value is passed |
| ---------- | -------------------------------------------------------------------------------------------------- |
| Go | a `string` holding the bytes (a Go `string` is a byte string) |
| Python | a `str` carrying the bytes with `surrogateescape` |
| TypeScript | a `Uint8Array` (a `string` holding a lone surrogate has no bytes and is refused, as a key is) |
| Rust | **cannot**: settings and query parameters take `String`, so a non-UTF-8 value is unreachable there |

A key that is not valid UTF-8 cannot be carried in any binding (a JSON object has no byte form for a key), and neither can a macro's name or value. Each is refused before any call. Where a binding cannot send the bytes, inline them in the SQL as `unhex('<hex>')`, built from hex digits only ([`limitations.md`](../limitations.md#binary-input-parameters-must-be-utf-8)).

## An unknown name refuses the whole call

Expand Down
Loading
Loading