SQLite column provenance: Map results to table.column origins
Use SQLite's column-origin APIs and a compile-time flag to recover which table.column produced each SELECT result.
TL;DR
- 01Use SQLite's column-origin APIs and a compile-time flag to recover which table.column produced each SELECT result.
- 02SQLite exposes column-origin metadata that lets client code map each result column back to its source table.column.
- 03The capability is available through C API functions such as sqlite3columnoriginname and sqlite3columntablename, and requires compiling SQLite with SQLITEENABLECOLUMNMETADATA enabled.
SQLite exposes column-origin metadata that lets client code map each result column back to its source table.column. The capability is available through C API functions such as sqlite3_column_origin_name and sqlite3_column_table_name, and requires compiling SQLite with SQLITE_ENABLE_COLUMN_METADATA enabled.
How to get column provenance from a prepared statement
Compile-time: enable SQLITE_ENABLE_COLUMN_METADATA when building SQLite. Many prebuilt SQLite binaries and language bindings omit this option, so confirm your distribution or rebuild if you need provenance information.
Prepare the statement: use sqlite3_prepare_v2 to compile the SELECT. After preparing but before finalizing, call the column-origin functions for each result column index.
API calls:
- sqlite3_column_origin_name(sqlite3_stmt*, int iCol) returns the originating column name, for example "id". It returns NULL if the result column is not a direct reference to a table column, or if provenance metadata is unavailable.
- sqlite3_column_table_name(sqlite3_stmt*, int iCol) returns the table name that supplies the column.
- sqlite3_column_database_name(sqlite3_stmt*, int iCol) returns the database file/schema name when attached databases are in use.
Typical usage pattern:
- Prepare the SELECT.
- For i from 0 to sqlite3_column_count(stmt)-1 call sqlite3_column_origin_name(stmt, i) and sqlite3_column_table_name(stmt, i).
- If origin name and table name are non-NULL, combine them as table.column to determine provenance. If NULL, fall back to column aliases from sqlite3_column_name or to client-side heuristics.
Limitations: expression columns, aggregates, and columns produced by complex query rewrites will often return NULL for origin name. The API reports origin only when the VDBE can trace a direct source column. Drivers that wrap SQLite may not expose these C API calls, so language-level libraries can limit access even if SQLite itself is built with the option.
SQL-level approaches and practical alternatives
When the C API is not available, or when working purely in SQL, use explicit naming in the query to preserve provenance. Two practical patterns work well:
Fully qualify columns in the SELECT list: SELECT users.id AS users_id. This makes the mapping explicit in the result set and survives most query plans.
Use AS to add table-prefixed aliases: SELECT u.id AS u_id, o.id AS o_id. Aliases are visible to all clients and require no special SQLite build options.
For debugging and exploratory work, sqlite_master and PRAGMA table_info(table) can be used to inspect table schemas. sqlite3_table_column_metadata is another C API function that returns declared type and NOT NULL constraints for a specific table.column and can help validate provenance once a mapping is known.
Examples and pitfalls: when a SELECT returns the same column name from two different tables without aliasing, sqlite3_column_origin_name will disambiguate only if provenance metadata is enabled and the column is a direct reference. If the column is wrapped in a function such as COALESCE or cast, the origin will generally be lost.
Why it matters
Recovering table.column provenance helps tooling that needs to show where values came from, for example ORMs, migration assistants, and SQL linters. The C API metadata gives reliable answers when available, but application developers should include explicit aliases or qualify columns in SQL when portability across SQLite builds and drivers is important.
Enable provenance support
Build SQLite with SQLITE_ENABLE_COLUMN_METADATA or confirm your binary exposes column metadata.
Prepare the statement
Use sqlite3_prepare_v2 to compile the SELECT before inspecting columns.
Query origin functions
Call sqlite3_column_origin_name and sqlite3_column_table_name for each result column index.
Fallback to aliases
If origin is NULL, rely on sqlite3_column_name or explicit AS aliases in the SQL.
Primary source
Simon Willison
simonwillison.netThe Brieftide Daily · 06:00
Briefs like this one, in your inbox every morning.