Spracherkennung für: .md vermutete Sprache: Abap {ABAP[65] Python[60] R[40]} [Methode: maximale Elemente, drei Dimensionen]
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## What This Is
DuckDB storage engine plugin for MariaDB. Creates tables with `ENGINE=DuckDB` that store data in DuckDB's columnar format and execute analytical queries through DuckDB's vectorized engine. Lives under `storage/duckdb/` in the MariaDB server tree.
## Build
```bash
# Build + install + start MariaDB (most common during development)
./build.sh -S -t Debug
# CI mode (build only, no install)
./build.sh -c -t Debug
# Build with packages
./build.sh -p -t RelWithDebInfo
```
The build directory is created as a sibling: `../DuckdbBuildOf_<source_dir_name>/`. DuckDB itself is built from source at `third_parties/duckdb/` via `ExternalProject_Add` and merged into a single `libduckdb_bundle.a`.
## Tests (MTR)
Tests use MariaDB's MTR (MySQL Test Runner) framework. Test files live in `mysql-test/duckdb/t/` with expected results in `mysql-test/duckdb/r/`.
```bash
# Run a single test
./run_mtr.sh create_table_column
# Run and record new expected output
./run_mtr.sh -r create_table_column
# Run all tests
./run_mtr.sh -a
# Run against an externally running MariaDB
./run_mtr.sh -e create_table_column
# Run all against extern server
./run_mtr.sh -a -e
```
## Architecture
All engine code is in the `myduck` namespace (except `ha_duckdb` which is in global scope per MariaDB handler convention).
> **Doc convention:** when this file (or a code comment) names a specific API to describe control flow (e.g. `SELECT_LEX::print()`), it must also name the file/function where that API is actually called. If no call site can be pointed to, describe the behavior instead of naming the API — do not imply a code path that isn't there.
### Key components
- **`ha_duckdb`** (`ha_duckdb.cc/h`) — MariaDB `handler` subclass. Entry point for all storage engine operations (open, close, read, write, DDL). Implements row-at-a-time interface for MariaDB, translating to DuckDB batch operations.
- **`DuckdbManager`** (`duckdb_manager.cc/h`) — Singleton owning the `duckdb::DuckDB` instance. Created once at plugin init, creates connections for each thread. Database file stored as `duckdb.db` in MariaDB data directory.
- **`DuckdbThdContext`** (`duckdb_context.cc/h`) — Per-thread context holding a `duckdb::Connection`, transaction state, and appenders. Attached to MariaDB's THD. Manages BEGIN/COMMIT/ROLLBACK lifecycle and session variable propagation (timezone, optimizer flags, collation).
- **DDL/DML Convertors** (`ddl_convertor.cc/h`, `dml_convertor.cc/h`) — Translate MariaDB SQL structures (TABLE, Field, Alter_info) into DuckDB-compatible SQL strings. Handle identifier quoting differences (MariaDB backticks → DuckDB double quotes) and type mapping.
- **`DeltaAppender`** (`delta_appender.cc/h`) — Batched write path. Accumulates INSERT/UPDATE/DELETE rows using DuckDB's Appender API into a temporary buffer table, then flushes as a single DuckDB DML statement at commit time. `DeltaAppenders` manages per-table appender instances.
- **Select handler / Query pushdown** (`ha_duckdb_pushdown.cc/h`) — Implements MariaDB's `select_handler` interface to push entire SELECT queries down to DuckDB. Registered via `hton->create_select` and `hton->create_unit`. Supports pure-DuckDB queries and cross-engine joins.
- **Cross-engine scan** (`cross_engine_scan.cc/h`) — Enables DuckDB to read from non-DuckDB tables (e.g. InnoDB) during cross-engine joins. Registers a `_mdb_scan` table function and a replacement scan callback in DuckDB. Uses a thread-local registry of external tables.
- **Type mapping** (`duckdb_types.cc/h`) — Converts between MariaDB field types and DuckDB types. `store_duckdb_field_in_mysql_format()` reads DuckDB values back into MariaDB row format.
### SQL generation conventions
DuckDB follows the SQL standard and delimits identifiers with **double quotes**, not backticks.
SQL reaches DuckDB by two routes:
- **Whole queries are forwarded verbatim.** SELECT and INSERT … SELECT are pushed down as the raw `thd->query()` text — see `extract_source_query()` in `ha_duckdb_pushdown.cc`. The engine does **not** re-print the whole query via `SELECT_LEX::print()`.
- **Only fragments are printed.** `Item`/`COND::print()` is used for per-table WHERE conditions in cross-engine scan (`ha_duckdb_pushdown.cc`) and for DDL default / `nextval` expressions (`ddl_convertor.cc`). DDL/DML convertors also build identifier strings directly from `Field`/`TABLE` metadata.
Both routes then pass through `backticks_to_double_quotes()` (`runtime/duckdb_query.cc`), which is where identifier requoting actually happens: backtick-delimited identifiers are rewritten to double-quoted ones and any embedded double quote is escaped (MDEV-40653). Raw forwarding additionally goes through `mariadb_query_has_lexical_mismatch()`, which refuses to forward SQL whose backslash-escape semantics differ between MariaDB and DuckDB.
See `docs/mariadb-duckdb-incompatibilities.md` for known function name rewrites and type mapping issues.
### DuckDB source and patches
DuckDB source is at `third_parties/duckdb/` (git submodule). One local patch is applied on top of the pinned submodule commit — `patches/duckdb-pr24061-setval.diff` (backport of upstream PR #24061 adding `setval()`, needed for AUTO_INCREMENT counter repositioning), applied via `PATCH_COMMAND` in `cmake/duckdb.cmake` and to be dropped when the submodule is bumped to a release containing the PR. Other compatibility is handled at runtime via `duckdb_mysql_compat.cc`. The build produces a static library; `_GLIBCXX_DEBUG` is explicitly undefined in CMakeLists.txt to avoid ABI mismatch with MariaDB's debug build.
### Configuration
`duckdb.cnf` — MariaDB config snippet that loads `ha_duckdb.so`. Installed to `/etc/my.cnf.d/`.
[Dauer der Verarbeitung: 0.12 Sekunden, vorverarbeitet 2026-10-08]