Fixes smaller catalog, API and extension problems: one row per constraint in `information_schema.check_constraints`, creating a VARIANT logical type through the C API, and requiring a constant `write_bbox` in the GeoJSON writer. Combines the PRs labeled `Ready To Merge` in https://github.com/duckdb-bot/duckdb/pulls below, on top of the current head of `main`. The changes of each PR are applied as one squashed commit. ## Changes applied (3 PRs) - duckdb-bot/duckdb#206: One row per constraint in information_schema.check_constraints - duckdb-bot/duckdb#126: Create a VARIANT logical type with its type info in duckdb_create_logical_type - duckdb-bot/duckdb#164: Require a constant write_bbox in the internal GeoJSON writer, instead of evaluating any expression while binding ## Original descriptions <details><summary>duckdb-bot/duckdb#206: One row per constraint in information_schema.check_constraints</summary> `information_schema.check_constraints` listed a `CHECK` once per referenced column: `CHECK (a > 0 AND b > 0)` appeared twice, while `CHECK (1 = 1)` was missing entirely (duckdb/duckdb#26343). DuckDB 1.5.6 behaves the same. The view unnested `constraint_column_names` from `duckdb_constraints()` to get the column for `NOT NULL` constraints. This also expanded each `CHECK` into one row per referenced column and dropped checks without column references. The view now returns one row per `CHECK` or `NOT NULL` constraint, taking the `NOT NULL` column from `constraint_column_names[1]` and leaving constraint text unchanged. asxvi’s open duckdb/duckdb#26357 makes the same view change. New cases in `test/sql/table_function/information_schema.test` cover distinct and repeated checks on the same two columns, constant checks, `NOT NULL` on either column, `UNIQUE` exclusion and attached databases; they fail on `main`. The table function, PostgreSQL catalog, constraint and catalog suites pass in reldebug and assertion builds, except for the Quack exit leak assertion also seen on `main`. The full unit suite passes apart from failures reproduced on `main`. Fixes duckdblabs/bot-issue-tracker#209 Related: duckdb/duckdb#26343 </details> <details><summary>duckdb-bot/duckdb#126: Create a VARIANT logical type with its type info in duckdb_create_logical_type</summary> The C API type returned by `duckdb_create_logical_type(DUCKDB_TYPE_VARIANT)` could not be used. Calling `duckdb_create_vector` with it or registering a table function with a VARIANT parameter of that type caused a segmentation fault on `main`. The reporter of duckdb/duckdb#24680 saw `duckdb_create_vector` return NULL instead. `DUCKDB_TYPE_GEOMETRY` and `DUCKDB_TYPE_INTEGER` work. `duckdb_create_logical_type` in `src/main/capi/v1/logical_types-c.cpp` builds every accepted type from its bare type id. VARIANT is physically a STRUCT and needs the child type information that only `LogicalType::VARIANT()` sets. Without it, `VectorStructBuffer` tried to read children from a type that had none. `duckdb_create_logical_type` now returns `LogicalType::VARIANT()` for `DUCKDB_TYPE_VARIANT`. A probe over all type ids found no other type created this way with the same failure; ANY and literal types still produce NULL vectors. A new case in `test/api/capi/v1/test_capi_variant.cpp` creates the type and a vector, registers a table function with a VARIANT parameter, and calls it with an integer, a nested value and a string. It crashes on `main` and passes with the change. The `[capi]` tests pass on relassert with sanitizers. All unit tests pass on reldebug except failures also seen on `main` on this machine (HTTP logging, external resource logging, thread and memory settings, an eviction queue test) and `test_variables.test`, which passes alone on both. No benchmark was run because only C API VARIANT type creation changes. Earlier pull request duckdb/duckdb#24713 made the same change and was closed by its author without merging. Fixes duckdblabs/bot-issue-tracker#197 Related: duckdb/duckdb#24680 </details> <details><summary>duckdb-bot/duckdb#164: Require a constant write_bbox in the internal GeoJSON writer, instead of evaluating any expression while binding</summary> Direct calls to `__internal_json_copy_to_geojson`, the scalar function behind `COPY ... TO ... (FORMAT GEOJSON)`, could fail when `write_bbox` was not constant. In assertion builds, `SELECT __internal_json_copy_to_geojson({'id': 1}, NULL, NULL, '', '', random() > 0)` failed with `INTERNAL Error: Assertion triggered ... allow_unfoldable || expr.IsFoldable()`. In release builds, `PREPARE j AS SELECT __internal_json_copy_to_geojson({'id': 1}, NULL, NULL, '', '', nextval('s') > 0)` failed with `INTERNAL Error: Attempting to commit a transaction that is read-only but has made changes` and invalidated the database; running the `SELECT` directly advanced the sequence once more during binding. A NULL `write_bbox` read an uninitialized boolean, reported by UBSan. Only direct calls reach this because `COPY` passes a constant. The function is new on `main`; v1.5.6 does not have it. `JSONCopyToGeoJSONBind` in `extension/json/json_functions/json_create.cpp` evaluated the last argument, `write_bbox`, during binding with `ExpressionExecutor::EvaluateScalar` and read it with `BooleanValue::Get`. It lacked the `IsFoldable` check already used for column and date format options, and did not handle NULL. The change reads `write_bbox` with `BindFunctionInput::GetConstant`, rejecting nonconstant arguments with a Binder Error (`... must be a constant expression`) and deferring an unresolved prepared parameter to `EXECUTE`. NULL means the option was not given, as for column options, and writes no bounding box. `COPY` is unchanged. `test/sql/json/copy_geojson_write_bbox_constant.test` covers `random()`, `nextval` directly and in a `PREPARE` with the sequence unchanged, a column, NULL, false and a prepared parameter; it fails on `main`. All unit tests pass on reldebug except failures also present on `main` on this machine and a parquet memory limit test that failed under load but passes when run alone, on `main` too. The JSON tests pass on relassert with sanitizers, without UBSan reports. No benchmark was run because the change is in binding only. This issue was found while working on duckdb-bot/duckdb#30, which handles folds through `Binder::FoldExpression`; this bind callback evaluated the argument itself. Fixes duckdblabs/bot-issue-tracker#603 </details>
DuckDB
DuckDB is a high-performance analytical database system. It is designed to be fast, reliable, portable, and easy to use. DuckDB runs in-process inside your application, so there is no separate server to manage and no external dependencies. It can also read remote files, query other databases, and connect to other DuckDB instances when needed. It provides a rich SQL dialect with support far beyond basic SQL: arbitrary and nested correlated subqueries, window functions, collations, and complex types (arrays, structs, maps). Its friendly SQL extensions add syntax that makes queries shorter and easier to write.
DuckDB is available as a standalone CLI application and has clients for Python, R, Java, Rust, Go, Wasm, and many more, with deep integrations with packages such as pandas.
For more information on using DuckDB, please refer to the DuckDB documentation.
Reads and writes any data
DuckDB reads and writes a wide range of file formats, including CSV, Parquet, JSON, and Excel, directly from local disk or from remote endpoints such as S3, HTTP(S), Azure, and Google Cloud Storage. For many of these formats, including CSV, Parquet, and JSON, loading data is as simple as referencing the file in the FROM clause:
SELECT * FROM 'myfile.csv';
SELECT * FROM 'myfile.parquet';
DuckDB also works with open lakehouse formats. DuckLake stores table metadata in a SQL database rather than in metadata files, which removes the need for a separate catalog server while still providing ACID transactions, snapshots, and time travel. DuckDB also supports the Apache Iceberg and Delta Lake formats. Refer to our Data Import section for more information.
Connects to other databases
DuckDB can attach to other database systems and query them in place, so you can read, join, and move data across engines without a separate ETL step. It speaks the native protocols of PostgreSQL, MySQL, and SQLite.
DuckDB instances can also connect to each other over the quack protocol, which turns a DuckDB instance into a server that other DuckDB clients attach to over HTTP.
Extensible
DuckDB has a modular extension mechanism: core extensions are bundled with DuckDB, while community and third-party extensions can be installed and loaded at runtime. Extensions add file formats, database connectors, and new functions, types, and more.
Installation
If you want to install DuckDB, please see our installation page for instructions.
SQL Reference
The documentation contains a SQL introduction and reference.
Development
For development, DuckDB requires CMake, Python 3 and a C++17 compliant compiler. In the root directory, run make to compile the sources. For development, use make debug to build a non-optimized debug version. You should run make unit and make allunit to verify that your version works properly after making changes. To test performance, you can run BUILD_BENCHMARK=1 BUILD_TPCH=1 make and then perform several standard benchmarks from the root directory by executing ./build/release/benchmark/benchmark_runner. The details of benchmarks are in our Benchmark Guide.
Please also refer to our Build Guide and Contribution Guide.
Support
See the Support Options page and the dedicated endoflife.date page.