SQL over the warehouse — guide
Class:
guide· audience: a techie querying the warehouse with SQL. The what is insql-design.md; the why the native provider inwarehouse-reasoning.md. The table names + shapes you query are catalogued inwarehouse-design.md(f2) andwarehouse-schema.md. This file is the CLI + workedSELECTs.
f0 — one command, every table
nornir warehouse query "SELECT * FROM bench_runs LIMIT 5"
- Table names are the warehouse table names —
bench_runs,test_results,symbol_facts,call_edges,coverage,surface_coverage,build_provenance,dep_graph_edges,release_lineage, … (bare names resolve; no schema prefix needed). The full list iswarehouse-design.mdf2. - Full DataFusion SQL —
WHERE,JOINacross tables,GROUP BY/ aggregates,ORDER BY,LIMIT. - Read-only + lock-tolerant — never mutates; if a live
nornir-serverholds the catalog lock you get a copied-aside snapshot (oneWARNING:line), not a deadlock. WHERE repo = '…'is cheap — it prunes whole Parquet files at plan time (partitioned tables), so scope your query and it reads only the slice you asked for.
f0b — discover the tables + columns first
Don't guess table or column names — ask the warehouse:
# List every queryable table:
nornir warehouse tables
# Describe one table's columns (name · Arrow type · nullability):
nornir warehouse tables call_edges
# snapshot_id Utf8 NOT NULL
# ts_micros Timestamp(µs, "+00:00") NOT NULL
# repo Utf8 NOT NULL
# caller_path Utf8 NOT NULL
# callee_ident Utf8 NOT NULL
# …
# Machine-readable (for tooling / jq):
nornir warehouse tables --json # ["agent_model_runs","airgap_events",…]
nornir warehouse tables call_edges --json # [{"name":"repo","data_type":"Utf8","nullable":false},…]
An unknown table name prints a clear error that lists every known table, so a typo tells you the right spelling. Discovery is cheap — it reads only catalog metadata, never a Parquet file — and is read-only + lock-tolerant just like query. This is the fast path to knowing what a SELECT can reference.
f1 — output formats
# Bordered text table (the default):
nornir warehouse query "SELECT repo, COUNT(*) AS n FROM call_edges GROUP BY repo"
# JSON array of row objects — pipe into jq / a script:
nornir warehouse query --format json \
"SELECT item_name, file FROM symbol_facts WHERE repo = 'nornir' LIMIT 10" | jq .
An empty result in JSON mode is a valid empty array ([]).
f2 — worked SELECTs
Filter one repo's symbols:
nornir warehouse query \
"SELECT item_name FROM symbol_facts WHERE repo = 'nornir' ORDER BY item_name"
Count rows per repo (aggregate + group by):
nornir warehouse query \
"SELECT repo, COUNT(*) AS n FROM call_edges GROUP BY repo ORDER BY n DESC"
Join two tables — every call edge out of a given symbol:
nornir warehouse query "
SELECT c.callee_ident
FROM symbol_facts s
JOIN call_edges c ON s.crate_name = c.crate_name
WHERE s.item_name = 'query'
ORDER BY c.callee_ident"
Latest bench runs for a repo/machine:
nornir warehouse query "
SELECT version, machine, ts_micros
FROM bench_runs
WHERE repo = 'nornir'
ORDER BY ts_micros DESC
LIMIT 5"
Release provenance:
nornir warehouse query "
SELECT release_id, repo, git_sha
FROM release_lineage
ORDER BY release_id DESC
LIMIT 10"
Browse a table's columns before writing a query with `nornir warehouse tables
f3 — from an MCP client (embedded only)
The warehouse_query MCP tool runs the same SQL and returns the rows as a JSON array. It runs embedded against the local warehouse — there is no SQL gRPC endpoint yet — so unset NORNIR_SERVER before calling it, or it returns an invalid_params error telling you to.
// MCP tool call
{ "name": "warehouse_query",
"arguments": { "sql": "SELECT repo, COUNT(*) FROM symbol_facts GROUP BY repo" } }
Discover the schema first with the warehouse_tables MCP tool (the sibling of warehouse_query, also embedded-only): no arguments returns the JSON list of queryable table names, and {"table": "<name>"} returns that table's columns as [{name,data_type,nullable}] — so a small/local agent can look up the exact FROM targets and column names before writing a SELECT, instead of guessing.
{ "name": "warehouse_tables", "arguments": {} } // → ["bench_runs","call_edges",…]
{ "name": "warehouse_tables", "arguments": { "table": "bench_runs" } } // → [{"name":"repo",…},…]
Gotchas
- Read-only — there is no
INSERT/UPDATEpath; facts get in through the writing functions (seewarehouse-guide.mdf3/warehouse-design.mdf3). - Scope your
WHERE— an unfiltered scan of a big table reads all history; aWHERE repo = '…'on a partitioned table prunes to that repo's files. - Unknown table name → the planner errors; run
nornir warehouse tablesfor the exact spelling (it lists every table), or checkwarehouse-design.mdf2. - MCP needs
NORNIR_SERVERunset — the SQL tool is embedded-only.