Repository navigation
Conversation
smithclay
force-pushed
the
compat/duckdb-2.0
branch
2 times, most recently
from
September 19, 2026 18:34
c1493e8 to
828b73c
Compare
smithclay
pushed a commit
that referenced
this pull request
Sep 21, 2026
The last docs pass said VARIANT buys smaller files but slower queries. That is true of the DuckDB this pins and false of the one it is heading for, so the docs now state it per version. Built the feature against PR #38's DuckDB 2.0 branch (v2.0-cyanoptera, 3a604ab) in a throwaway tree and ran the same queries over the same Parquet files on both engines, 200k log records: 1.5 JSON -> VARIANT 2.0 JSON -> VARIANT string key, repeated bags 3ms -> 445ms 28ms -> 3ms string key, per-record bags 45ms -> 256ms 52ms -> 3ms GROUP BY an attribute 34ms -> 483ms 30ms -> 4ms numeric key 59ms -> 317ms 53ms -> 124ms 2.0's shredded execution and extraction pushdown read the one shredded subcolumn instead of rebuilding the bag, which is what flips the result: the idiom does not matter (variant_extract, the [] shorthand and a VARIANT comparison all measure the same), and touching the column without extracting anything drops from 468ms to 130ms. Numeric keys do not get the same treatment yet. Ingest changes little: on 2.0 the posted-throughput penalty disappears into the noise and the seal penalty drops from +42% to +25%, with the same -40% on disk. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LHzXbDhmfExBgUGrwBybbj
smithclay
force-pushed
the
compat/duckdb-2.0
branch
from
September 21, 2026 00:55
828b73c to
3c44d80
Compare
Move the DuckDB submodule from an old `main` commit (8616efa, 2163 commits behind) to the tip of `v2.0-cyanoptera` (3a604ab), the feature-frozen 2.0 release branch. No v2.0.0 tag exists yet — the branch is the newest 2.0 ref available — so `.gitmodules` now tracks it instead of `main`, and the CI `duckdb_version` inputs point at the same ref. `extension-ci-tools` moves to its `main` tip, which is what builds against the 2.0 branch. Rebasing onto main pulled in `otlp_column_promote.cpp`, which was added after this branch was cut and still included `duckdb/main/materialized_query_result.hpp`. DuckDB 2.0 removed that header along with `MaterializedQueryResult`; `Connection::Query` now returns `unique_ptr<QueryResult>`. The file only uses `HasError()`/`GetError()` from `BaseQueryResult`, so the include moves to `duckdb/main/query_result.hpp`. Also resolved during the rebase: `otlp_server_list` now emits one row per listener (main's N-listener refactor) using `SetChildCardinality`, and the Quack docs component keeps its `token` prop while using 2.0's CONNECT form. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018nRtuxxexQqGerw5pqAVB9
`duckdb_version` is both the git ref checked out and the version string stamped into the built binaries. `v2.0-cyanoptera` is a branch name, not a semver, so DuckDB's CMake leaves it unparsed and the resulting binaries resolve extensions under extensions.duckdb.org/v2.0-cyanoptera/, which does not exist. Only the published v2.0.0-alpha39998 has extension binaries, and there is no git ref for it. Harmless for these two jobs -- no test in test/sql INSTALLs an extension -- but it is why the Docker/daemon path, the host duckdb CLI downloads and the pages.yml pins stay on v1.5.5 for now. Record that in the workflow so the next person does not have to rediscover it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018nRtuxxexQqGerw5pqAVB9
Rebasing onto main (511c5b2) pulled in the CLI (#68), the `--init-sql` / shutdown-seal work (#70), the config-surface collapse (#73) and the `duckdb_functions()` metadata pass (#76). Three of those touch APIs 2.0 changed, so they need the same treatment the rest of this branch already got: - `src/server/commands.cpp`: DuckDB 2.0 removed `MaterializedQueryResult` along with `duckdb/main/materialized_query_result.hpp`, and folded `RowCount()` / `ToString()` / `GetValue()` into `QueryResult`. The three `Cast<MaterializedQueryResult>()` sites call those directly now, and `PrintBox` takes a `QueryResult &`. `BaseQueryResult::type` is private in 2.0, so the "did this statement produce a table?" check goes through `GetResultType()`. - `src/otlp_start_stop.cpp`: the no-argument `otlp_stop()` overload (#70) pages its rows out through two more `SetCardinality` calls, which 2.0 renamed to `SetChildCardinality`. Its bind signature takes `vector<Identifier> &names` like every other bind on this branch. - `src/otlp_uri.cpp`: `otlp_uri_parser` is now registered through `OtlpDocumented` (#76). The function is built first so `SetFallible()` still applies — 2.0 requires it of a scalar function that throws — and then handed to the wrapper. `src/server/main.cpp` drops the now-unused `database_manager.hpp` include, and AGENTS.md's `--init-sql` note no longer points at `SetDefaultDatabase`, which this branch removed. Verified: every extension, daemon and harness translation unit compiles against the 2.0 headers (`-fsyntax-only` over the full compile database), and clang-format 11.0.1 is clean on every changed file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LgQrTbecUyFCwpr4mumUwR
Two behaviors main relies on changed in 2.0. Both surfaced as real test failures after the rebase, not as compile errors. `duckdb_functions()` parameter names (#76). A `FunctionDescription`'s `parameter_names` used to win outright; in 2.0 they are only a fallback, consulted when the count of the function's *own* signature names does not match the rendered parameter list (`GetParameterNames` in `duckdb_functions.cpp`). A `ScalarFunction` can carry real names, so `otlp_uri_parser` is now built from a named `FunctionParameter` and reports `listen_uri` again instead of `col0`. A `TableFunction` cannot -- it takes a bare `vector<LogicalType>` and its extractor emits `col0`, `col1`, ... unconditionally -- so on 2.0 every reader and control-plane table function reports `colN` whatever its description says. `function_metadata.test`'s placeholder assertion is scoped to the scalar function accordingly, with the mechanism written down; the readers keep their real `parameter_names` so they document the argument and take effect if upstream restores the override. `query`'s echo of the user's own SQL (#68). 2.0 reimplemented `Connection::ExtractStatements` on top of the lazy statement iterator, which -- unlike `ClientContext::ParseStatements`, still private -- does not run `ProcessError`. A parser error therefore arrives stripped of the "LINE n: ... ^" context that `RunDataCommand`'s `keep_sql_context` branch exists to pass through, and `duckdb-otlp query "SELCT 1"` reported a bare `syntax error at or near "1"`. The parse is wrapped so the statement the user wrote is put back on the message. Verified against 3a604ab: `make test` 23/23, `otlp_arrow_harness` 6 assertions, `otlp_seal_harness` 168 assertions, `pytest test/server` 244 passed. The 2 remaining server-test failures are this branch's documented blocker -- `INSTALL ducklake` 404s because DuckDB publishes no 2.0 extension binaries yet -- and are unrelated to these changes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LgQrTbecUyFCwpr4mumUwR
Still no v2.0.0 tag, so this tracks the newest 2.0 ref: duckdb 3a604ab -> fc9d6e9 (1233 commits). extension-ci-tools now has its own v2.0-cyanoptera branch, so the submodule, .gitmodules and the reusable-workflow refs follow it instead of `main`, which will move on to 2.1. API changes on the tip: - Table functions declare parameters through a Python-style FunctionSignature; `TableFunction::named_parameters` and `arguments` are gone. otlp_serve / otap_serve declare their optional options as a typed "**kwargs" schema (WithTypedKwargs, the mechanism read_csv uses): an option the call leaves out is not passed, so the bind keeps its own defaults exactly as before. A side effect is that duckdb_functions() now reports the options by their real names. - QueryResult lost GetValue() and QueryResultType. `query` renders through QueryResult::ToBox (the BoxRenderer main switched to, so `--format box` stays a real box, not ToString()'s debug form); the seal harness reads its count through Fetch(). Linking changed, and it broke the daemon silently -- it compiled, then `duckdb-otlp convert --to x.parquet` failed with `Copy Function "parquet" is not in the catalog`: - A statically linked extension now registers itself only if the program roots it, via link_extension_libraries. That reads the link set DuckDB resolves after its extension loop, and this CMakeLists runs inside the loop, so the daemon and both harnesses linked no parquet/json/core_functions at all. otlp_link_duckdb_extensions defers the call to the end of configure. - Loading an extension config no longer implies linking it into the shell and unittest; extension_config.cmake asks with duckdb_extension_statically_link. Without it build/release/duckdb had no otlp_serve. Verified against fc9d6e9: make test 23/23 (387 assertions), otlp_seal_harness 204 assertions, otlp_arrow_harness 6, pytest test/server 245 passed. The 2 failures are the known blocker (no published ducklake for a 2.0 dev build). DuckLake seal verified separately against a ducklake built from source at the commit DuckDB's 2.0 branch pins (e8924cf). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
smithclay
force-pushed
the
compat/duckdb-2.0
branch
from
October 3, 2026 18:30
c62e70f to
ff49054
Compare
…king The function-metadata section still described v1.5: options in an unordered_map rendered as colN. On the 2.0 tip duckdb_functions() renders names from the function's own FunctionSignature, typed **kwargs options are listed by name in declaration order, and a bare-LogicalType positional is named colN by AddParameter(type), not by the extractor. Point at AddPositionalOnly as the way to name a reader's argument. The Build System section gains the two things a fresh session would trip over: the submodules and workflow refs track v2.0-cyanoptera until a tag exists, and an embedding executable must link DuckDB's extensions through otlp_link_duckdb_extensions, since a direct link_extension_libraries call links nothing yet still builds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
daemon-compile could not pass on a DuckDB 2.0 development build: the default local-ducklake mode INSTALLs ducklake at startup, no ducklake is published for a dev build, and the 2.0 alpha's binary null-derefs on load against the branch tip. No version string fixes that, because the problem is the coupling itself -- the daemon only worked when a published extension build happened to match its ABI. So the daemon stops downloading the extension its default mode needs: - DUCKDB_OTLP_BUILT_IN_EXTENSIONS (CMake list) links extensions into DuckDB. extension_config.cmake takes each from DuckDB's own pinned config (duckdb/.github/config/extensions/<name>.cmake: the commit and patches DuckDB builds against this source), so the ABI matches by construction. - `make server-release` -- the path Docker and both daemon CI jobs take -- sets it to ducklake and first builds CRoaring, ducklake's one dependency, into build/deps, since those builds run without vcpkg. v4.7.2 rather than vcpkg's 4.4.2, whose package config CMake 4 rejects. The extension distribution builds are unchanged. - Core(name) reports BUILT_IN when LinkedExtensionRegistry says the binary links it, so no INSTALL/LOAD is emitted and the banner says "built in". Asking the binary rather than a build flag means the two cannot drift. - The image stops priming ducklake. quack stays a runtime install: on 2.0 it draws its tokens from the writable crypto module only httpfs (OpenSSL) provides, so building it in means building httpfs in, against the image's no-libssl design. test_init_sql_adds_a_parquet_destination_next_to_the_ducklake_catalog read the daemon's catalog back with the host's duckdb==1.5.6, which cannot open a 2.0-format database (storage version 69). It now reads it back through the binary under test (`duckdb-otlp query`), which is still a real DuckLake read and no longer depends on the host's DuckDB version. Verified: local-ducklake daemon with an empty extension cache ingests, seals and reads back with zero downloads; pytest test/server 247/247 both on macOS and against the Docker-built linux/arm64 daemon-export binary; make test 23/23, seal harness 204, arrow harness 6. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… 2.0 clang-format 11 wanted two whitespace changes (otlp_start_stop.cpp, server_config.cpp). The daemon smoke failed because Quack cannot load in a 2.0 daemon: no extensions are published for the 2.0 development build, and the image's offline cache holds v1.5.6 builds whose init crashes. smoke_test.py gains --verify restart, which seals by SIGTERM (graceful otlp_stop), requires a clean exit, and reads the count back with the image's own query subcommand over the same /data volume. Both CI smoke jobs use it and no longer install a host duckdb CLI. The default stays --verify quack.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
fc9d6e9(rebased onmain@c3dff30)FunctionSignature-based table-function parameters and the reshapedQueryResultDuckDB 2.0 tracking
There is still no
v2.0.0tag (latest release is v1.5.6), so thev2.0-cyanopterabranch tip is the newest 2.0 ref:duckdbsubmodule →fc9d6e9(tip ofv2.0-cyanoptera, 2026-10-02), up from3a604ab(1233 commits)extension-ci-tools→969bc76. ci-tools now has its ownv2.0-cyanopterabranch, so the submodule,.gitmodules, and the reusable-workflow@ref/ci_tools_versionfollow it instead ofmain, which will move on to 2.1duckdb_versioninMainDistributionPipeline.ymlstaysv2.0-cyanopteraduckdb_versionis both the git ref and the version stamped into artifacts. A branch name is not a semver, so the stamped version has no published extensions to resolve. Pin to the tag once 2.0.0 lands.What changed on the tip (
3a604ab→fc9d6e9)APIs
TableFunction::named_parameters/argumentsare gone; parameters are a Python-styleFunctionSignature.otlp_serve/otap_servenow declare their options as a typed**kwargsschema (WithTypedKwargs, the same mechanismread_csvuses). An omitted option is not passed, so bind defaults behave exactly as before. Side effect:duckdb_functions()now lists those options by their real names instead ofcolN.QueryResultlostGetValue()andQueryResultType.query --format boxrenders throughQueryResult::ToBox, which keeps main's BoxRenderer output rather thanToString()'s debug form, and the seal harness reads its count throughFetch().Linking (silent breakage)
link_extension_libraries. That function reads the link set DuckDB resolves after its extension loop, and ourCMakeLists.txtruns inside that loop, so the daemon and both harnesses linked no parquet/json/core_functions at all. Everything compiled, thenduckdb-otlp convert --to x.parquetfailed withCopy Function "parquet" is not in the catalog.otlp_link_duckdb_extensionsdefers the call to the end of configure.extension_config.cmakenow callsduckdb_extension_statically_link(otlp); without it,build/release/duckdbhad nootlp_serve.Validation
On
fc9d6e9(macOS arm64):GEN=ninja make release: cleanmake test: 23/23 files, 387 assertionsotlp_seal_harness: 11 cases, 204 assertionsotlp_arrow_harness: 2 cases, 6 assertionspytest test/server: 247/247 (see below)--mode parquet): OTLP/HTTP protobuf, NDJSON, and gzip ingest → 202; shutdown seals;queryreads back through the Parquet views;exportwrites NDJSONv2.0.0-alpha39998binary null-derefs on load (ABI mismatch: it was built fromeb7b95df82). So I built ducklake from source at the commit DuckDB's 2.0 branch pins (e8924cf) and ranotlp_serve(catalog := 'lake'): POST logs/traces/metrics →otlp_flushsealed all rows in one snapshot, 0 seal failures,otlp_stopdropped 0daemon-compile: fixed by building ducklake into the daemonThis used to be a known failure. The default
local-ducklakemode ranINSTALL ducklakeat startup, and no ducklake is published for a 2.0 dev build. Thev2.0.0-alpha39998binary null-derefs against the tip. No version string fixes this, because the real problem is that the daemon only works when a published extension happens to match its ABI.Now ducklake is linked into the daemon instead (
a4d5b615):DUCKDB_OTLP_BUILT_IN_EXTENSIONSlinks extensions taken from DuckDB's own pinned configs (duckdb/.github/config/extensions/<name>.cmake: the commit and patches DuckDB builds against this source), so the ABI matches by construction.make server-release(Docker and both daemon CI jobs) sets it toducklakeand first builds CRoaring, ducklake's only dependency, intobuild/deps. The extension distribution builds are unchanged.Core(name)reportsBUILT_INwhenLinkedExtensionRegistrysays the binary links it, so noINSTALL/LOADis emitted. Because this asks the binary itself rather than a build flag, the two cannot drift.test_init_sql_adds_a_parquet_destination_next_to_the_ducklake_catalognow goes through the binary under test. The host'sduckdb==1.5.6cannot open a 2.0-format database (storage version 69).Verified:
local-ducklakedaemon with an empty extension cache ingests, seals and reads back, with zero downloads.pytest test/serverpasses 247/247 on macOS and against the Docker-builtlinux/arm64daemon-exportbinary.Still open
docker-smoke, and the cloud modes (httpfs/aws/iceberg/postgres/gcs) still need published extensions, and the Dockerfile still pinsDUCKDB_VERSIONto v1.5.6 for them.pages.yml, the hostduckdbCLI downloads,duckdb==1.5.6in the server tests, and theMakefile's WASMVERSION_FIELDall stay on the 1.5 line.Notes
src/otlp_column_promote.cppincludesduckdb/main/query_result.hpp; 2.0 removedmaterialized_query_result.hpp.otlp_server_listemits one row per listener usingSetChildCardinality.windows_amd64builds against DuckDB 2.0 here for the first time, so watch it on the next run. The deferredcmake_language(DEFER)call only applies inside the non-Windows daemon/harness block.FunctionSignature(AddPositionalOnlyis how to name a reader's argument), and embedding executables must link DuckDB's extensions throughotlp_link_duckdb_extensions.