Skip to content

catch up to ABI 0.14 - #4

Merged
tamnd merged 1 commit into
mainfrom
abi-014
Aug 22, 2026
Merged

tamnd merged 1 commit into
mainfrom
abi-014

Conversation

@tamnd

@tamnd tamnd commented Aug 22, 2026

Copy link
Copy Markdown
Owner

The suite has been red since the engine moved. Two ABI revisions landed and two more words became reserved, and this covers both.

What the ABI added. 0.13 added zu_conn_table_name and 0.14 added zu_value_bytes with ZU_TYPE_BYTES to go with it. The wrapper now has all three, the version check in CMakeLists says 0.14, and the test that asserts the wrapper and the library agree about the ABI passes rather than fails.

Value::as_bytes is a std::span<const std::uint8_t> into the result, not copied and not NUL terminated, on exactly the terms as_string is. Row::get reads it as that span, or as a std::vector<std::uint8_t> for a caller who wants the octets to outlive the result they came out of. Text and octets are separate types in both directions and reading one as the other is refused, which is the point of the engine having a second type at all: a blob with a zero octet in it ends before it starts when read as text, and a blob that happens to be valid UTF-8 is still a blob.

Connection::table_name answers a std::optional<std::string>, and nothing rather than a failure when no table has that id, because an id no table has is an answer to the question. It copies where the rest of the header borrows. The pointer the ABI hands back is good only until the next call of the same function on the same connection, so a view over it dangles a line later, and a lifetime nobody can see is worse than an allocation everybody can. It is also the one call on a connection the ABI returns no status for, so the closed handle it would otherwise dereference is caught here instead, and there is a case for that.

The reserved words are big, small and at. The fix is not to rename the columns. The engine's own message says to write the name in accent quotes, so the aliases are quoted and the columns keep the names the cases were written around, which holds whether or not the grammar reserves another word next month. A property is read by name and needs no quoting; only an alias after AS does.

Verified on a Linux box with gcc 13 against libzu built from engine HEAD, at C++23 and at the C++20 floor: 35 of 35 green, up from 31 of 35. Every claim above was checked against the running engine before it was written down, including that an empty byte string is a byte string rather than a null and that a table id nothing owns comes back as a null pointer.

One thing this does not fix. Under ctest -j the suite is flaky, and it was before this change: every file is built twice, at C++23 and at the C++20 floor, so two processes run the same cases at once, and the temp directory helper names its directories after the case and a counter that restarts in each process and then clears whatever is already there. The two builds delete each other's databases. That is a separate bug with a separate fix and it is the next PR.

The engine moved twice since this wrapper was written and the suite has
been red since. 0.13 added zu_conn_table_name and 0.14 added
zu_value_bytes with a type to go with it, and separately two more words
became reserved, which broke four cases and one example that had used
them as aliases.

zu_value_bytes is Value::as_bytes, a span of octets pointing into the
result on the same terms as a string: not copied, not NUL terminated,
good for as long as the result is. Row::get reads it as that span or as
a vector for a caller who wants the octets to outlive the result they
came from. Octets and text are separate types both ways, so reading one
as the other is refused rather than guessed at, which is the whole point
of the engine having a second type: a blob with a zero in it ends early
as text and a blob that happens to be valid UTF-8 is still a blob.

zu_conn_table_name is Connection::table_name, and it answers nothing
rather than failing when no table has that id, because an id no table
has is an answer to the question. It copies where the rest of the header
borrows, and that is deliberate. The pointer the ABI hands back is good
only until the next call of the same function on the same connection, so
a string_view over it dangles one line later, and a lifetime nobody can
see is worse than an allocation everybody can. It is also the only call
on a connection the ABI returns no status for, so the closed handle it
would otherwise dereference is caught here instead.

The reserved words are big, small and at, and the fix is not to rename
the columns. The engine's own message says to write the name in accent
quotes, so the aliases are quoted and the columns keep their names,
which holds whether or not the grammar reserves another word next month.
A property is read by name and needs no quoting; only an alias after AS
does.
@tamnd
tamnd merged commit 33ca5e2 into main Aug 22, 2026
5 checks passed
@tamnd
tamnd deleted the abi-014 branch August 22, 2026 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant