DuckDB Under the Microscope: What 67 AST Tools Found Inside the Analytical Engine
We benchmarked all 67 prod-code AST tools against duckdb/duckdb: 681,000 lines of modern C++, QueryResult slicing, and catch2 matcher guardrails.

On this page · 4 sections
duckdb/duckdb is a high-performance in-process analytical SQL database management system, providing vectorized execution, columnar storage, and seamless zero-copy integration across Python, R, and Rust environments.
Spanning 681,473 lines of modern C++ across 3,273 source files in src/ (with 350,004 declarations indexed monorepo-wide), DuckDB represents a monumental benchmark for compiler-grade tooling. The engine makes extensive use of C++17 templates, multi-tiered query planner abstractions, and vectorized vector pipelines.
We evaluated all 67 prod-code AST tools against duckdb/duckdb (commit a2af0a7bba) executing on remote 32-core LAN nodes with zero local laptop CPU load.
Semantic Search and Slicing the Query Execution Spine
Executing SQL queries in DuckDB flows from high-level client interfaces down into vectorized chunk operators. Locating foundational execution hubs across thousands of templated headers requires ranking symbols by typed graph centrality.
We queried reciprocal-rank-fusion (RRF) search for ClientContext across 350,004 indexed declarations:
$ prod-code search "ClientContext"
10 hit(s) for `ClientContext` in 4172 ms (350004 declarations, 4971 files; ranked by words and typed graph only; 0 of 350004 declarations embedded so far, the rest in the background)
6. [function] Event::GetClientContext src/include/duckdb/parallel/event.hpp:63
ClientContext &GetClientContext();
attribution [score 0.0152]: lexical: rank 6 (matched client, context)
7. [function] Pipeline::GetClientContext src/include/duckdb/parallel/pipeline.hpp:125
ClientContext &GetClientContext();
attribution [score 0.0149]: lexical: rank 7 (matched client, context)
8. [class] ClientContext extension/json/include/json_functions.hpp:20
class ClientContext;
attribution [score 0.0148]: graph: rank 1 (class 'ClientContext' in-degree 3671 (centrality 5.23))
In 4,172 ms, graph centrality ranked class ClientContext (with an in-degree of 3,671 call and type references) as the structural center of the engine.
We executed backward AST program slicing on Connection::Query at src/main/connection.cpp:81:
$ prod-code slice src/main/connection.cpp --line 81 --depth 1
=== src/main/connection.cpp
[method] Connection::Query src/main/connection.cpp:81-83 (the seed)
unique_ptr<QueryResult> Connection::Query(const string &query) {
return context->Query(query, QueryParameters());
}
=== src/include/duckdb/main/query_result.hpp
[class] QueryResult src/include/duckdb/main/query_result.hpp:65-275 (depth 1, used by Connection::Query)
class QueryResult {
public:
DUCKDB_API virtual ~QueryResult();
DUCKDB_API const ResultFormat &Format() const;
DUCKDB_API void Materialize();
DUCKDB_API void Complete();
...
template <class FORMAT = ChunkFormat>
unique_ptr<typename FORMAT::T> Fetch() {
if constexpr (std::is_same<FORMAT, ChunkFormat>::value) {
auto chunk = FetchRaw();
if (!chunk) return nullptr;
chunk->Flatten();
return chunk;
}
}
...
shared_ptr<ClientContext> context;
shared_ptr<BufferedData> buffer;
};
The AST slicer isolated the query submission seed in connection.cpp, traversing header dependencies to extract the full QueryResult data chunk streaming contract in query_result.hpp.
Structural Invariant Queries and Extension Clones
DuckDB uses typed C++ exception hierarchies to safeguard database invariants. Internal assertion failures throw InternalException, signaling unhandled execution states or optimizer bugs.
We queried throw InternalException($$$) across all repository files using structural AST matching:
$ prod-code structural-search 'throw InternalException($$$)'
2277 match(es) in 693 file(s) (5001 scanned in 18848.71ms)
• benchmark/include/duckdb_benchmark.hpp:48:4 throw InternalException("Unknown profiling option \"%s\"", instance.configuration.profile_info)
└─ [$$$ = "Unknown profiling option \"%s\"", instance.configuration.profile_info]
• extension/core_functions/aggregate/algebraic/avg.cpp:295:3 throw InternalException("Unimplemented average aggregate")
└─ [$$$ = "Unimplemented average aggregate"]
• extension/core_functions/aggregate/distributive/approx_count.cpp:40:3 throw InternalException("ApproxCountDistinct - count must be at most vector size")
└─ [$$$ = "ApproxCountDistinct - count must be at most vector size"]
• extension/core_functions/aggregate/holistic/reservoir_quantile.cpp:39:4 throw InternalException("Memory allocation failure")
└─ [$$$ = "Memory allocation failure"]
In 18,848 ms, the tool scanned 5,001 translation units and indexed all 2,277 internal exception call sites with bound argument expressions.
Running AST subtree duplicate detection revealed over 5,500 clone groups, primarily concentrated in third-party parsers and unicode tables. Clone Group #1518 matched 33 identical 12-line AST subtrees in third_party/utf8proc/utf8proc_data.cpp:
$ prod-code duplicates --min-lines 12 --group 1518
[Clone Group #1518] 12 lines | 33 occurrences (Type-2 (Parameterized))
• Occurrence 1: third_party/utf8proc/utf8proc_data.cpp:9038-9049
• Occurrence 2: third_party/utf8proc/utf8proc_data.cpp:9050-9061
• Occurrence 3: third_party/utf8proc/utf8proc_data.cpp:9062-9073
• Occurrence 4: third_party/utf8proc/utf8proc_data.cpp:9256-9267
Preview:
│ {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 26, UINT16_MAX, UINT16_MAX, 9560...},
│ {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, 27, UINT16_MAX, UINT16_MAX, 9562...},
Detecting these repetitive tables allows automated verification that generated parser assets match upstream unicode specifications without manual spot-checking.
Cross-Class Overload Collisions and Matcher Guardrails
In large C++ codebases, identical method names frequently exist across independent classes. Inverting StringUtil::EndsWith requires ensuring that unrelated classes containing EndsWith—such as Identifier::EndsWith—are not incorrectly captured.
We executed invert-boolean on StringUtil::EndsWith:
$ prod-code invert-boolean --path src/common/string_util.cpp --to DoesNotEndWith "StringUtil::EndsWith"
--- a/src/function/table/read_duckdb.cpp
+++ b/src/function/table/read_duckdb.cpp
@@ -533,7 +533,7 @@
auto table_name = ReplacementScan::GetFullPath(input);
auto lower_name = StringUtil::Lower(table_name);
- if (!StringUtil::EndsWith(lower_name, ".db") && !StringUtil::Contains(lower_name, ".db?") &&
- !StringUtil::EndsWith(lower_name, ".ddb") && !StringUtil::Contains(lower_name, ".ddb?") &&
- !StringUtil::EndsWith(lower_name, ".duckdb") && !StringUtil::Contains(lower_name, ".duckdb?")) {
+ if (StringUtil::DoesNotEndWith(lower_name, ".db") && !StringUtil::Contains(lower_name, ".db?") &&
+ StringUtil::DoesNotEndWith(lower_name, ".ddb") && !StringUtil::Contains(lower_name, ".ddb?") &&
+ StringUtil::DoesNotEndWith(lower_name, ".duckdb") && !StringUtil::Contains(lower_name, ".duckdb?")) {
return nullptr;
}
not rewritten (2 reference(s) that are not a call — a function used as a value keeps its old meaning under its new name; nothing is written while any remains):
third_party/catch/catch.hpp:5035:20 `EndsWith` used as a value
third_party/catch/catch.hpp:5060:40 `EndsWith` used as a value
the analyzer rejects the result:
In included file: expected member name or ';' after declaration specifiers [expected_member_name_or_semi] (src/include/duckdb/common/identifier.hpp:87:18)
nothing was written; pass `apply: true` to make these edits
The transformation adjusted call sites in read_duckdb.cpp, cleanly removing outer ! negations. However, the analyzer refused to write modifications to disk: DUCKDB_API bool EndsWith(...) const in identifier.hpp collided with the un-scoped transformation, while Catch2 test matchers in catch.hpp referenced EndsWith as a value. The compiler-backed safety guardrail prevented corrupted header definitions.
In-Memory C++ Header Pre-Flight Compilation
Modifying core utility headers in DuckDB triggers recompilation of hundreds of translation units. Testing speculative refactorings locally wastes CPU cycles and clutters build trees with object caches.
prod-code validate compiles proposed modifications in a remote memory overlay under clangd before files are touched on disk.
We submitted src/common/string_util.cpp clean, followed by an injected type error:
$ prod-code validate src/common/string_util.cpp --from src/common/string_util.cpp
src/common/string_util.cpp: 0 error(s), 0 warning(s)
(4 diagnostic(s) the file already had before this edit are not counted)
[prod-code] analysed in 2.68s
$ prod-code validate src/common/string_util.cpp --from /tmp/broken_string_util.cpp
src/common/string_util.cpp: 1 error(s), 0 warning(s)
(4 diagnostic(s) the file already had before this edit are not counted)
error: Use of undeclared identifier 'NonExistentType' [undeclared_var_use] (src/common/string_util.cpp:59:50)
[prod-code] analysed in 2.82s
In 2.82 seconds, remote clangd verified the C++ AST against DuckDB’s full header hierarchy, surfaced the undeclared type identifier, and protected the repository from uncompilable code changes.
In large-scale C++ analytical engines where templates, multiple overloads, and macro-heavy test frameworks coexist, automated refactorings cannot succeed through unconstrained lexical replacement; AST transformations must enforce cross-class symbol disambiguation and validate proposed translation units entirely in memory before touching disk.
Cite this article
Alexander Panasenko (2026-09-30). DuckDB Under the Microscope: What 67 AST Tools Found Inside the Analytical Engine. https://prod.codes/blog/duckdb-under-the-microscope-67-ast-tools/