Repository navigation
Push filters down into SQLite scans - #274
Merged
Merged
Conversation
Filters that SQLite evaluates exactly like DuckDB are added to the WHERE clause of the scan query: BIGINT columns, the rowid, and VARCHAR columns with TEXT affinity in a UTF-8 database (compared with COLLATE BINARY). All other pushed down filters are evaluated in DuckDB as part of the scan. Pushdown can be disabled with SET sqlite_enable_filter_pushdown = false.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes https://github.com/duckdblabs/duckdb-internal/issues/11567
This is the first PR in a series to make DuckLake's metadata catalogs pluggable. The SQLite-, Postgres- and MySQL-specific code in DuckLake moves into the matching extensions, so that DuckLake itself has no catalog-specific logic (duckdb/ducklake#882). Following the direction in duckdb/ducklake#1126, catalogs would register themselves with DuckLake rather than being built into it. We are starting with SQLite.
Part of DuckLake's SQLite code exists only because
sqlite_scanpushes no filters into SQLite. The main case is the stats override from duckdb/ducklake#1814. Without pushdown, every filtered DuckLake read copied all ofducklake_file_column_statsinto DuckDB, soSQLiteMetadataManagernow reads the stats throughsqlite_queryinstead. With this PR, DuckLake's generic stats query is filtered inside SQLite, and that override can go.Planned next steps:
sqlite_scannerpin and delete the stats overrideChanges
Scans of attached SQLite tables (
ATTACH ... (TYPE SQLITE)) now take pushed-down filters.sqlite_scan()andsqlite_attach()are unchanged.Filters go into the WHERE clause of the SQLite query only where SQLite compares values exactly like DuckDB:
rowiddoes not hide itCOLLATE BINARY, so aNOCASEcolumn returns the same rows as it would in DuckDBThe other pushed-down filters are evaluated by DuckDB inside the scan. This uses
TableFilterStateandColumnSegment::FilterSelection, as the Parquet reader does. It applies to:sqlite_all_varcharFilters with a NUL byte in a string constant also stay in DuckDB as SQLite stops reading the query text at the first NUL.
Pushdown is on by default.
SET sqlite_enable_filter_pushdown = falseturns it off.Behaviour change: rows that SQLite filters out are never read. A value that doesn't match its column's declared type no longer raises a type-mismatch error when the filter excludes its row. Rows that pass the filter are checked as before.
Known cost: a column used only in a filter is still selected from SQLite because the scan does not set
filter_prune. This can be a follow-up.Why not
supports_pushdown_typeThe usual way to keep some columns' filters in DuckDB is
TableFunction::supports_pushdown_type. As of v2.0.0 that planner path has two bugs:Extra output column. When a filter is declined on a scan withFixed by Fix volatile filter pushdown, constant_or_null folding, statistics and projection placement duckdb#27757projection_ids, the filter column is added to the scan output and never removed. It then fails withINTERNAL Error: Attempted to access index 3 within vector of size 3virtual_columns.atwhen the function has noget_virtual_columnsEvaluating the declined filters inside the scan avoids these bugs. I'll open follow-up issues for the rowid bug.
Testing
test/sql/storage/attach_filter_pushdown.testcovers:EXPLAINchecks;rowid;NOCASEcollation and NUMERIC affinity;data/db/utf16.db;sqlite_all_varchar.The test fails if any one of these five safeguards is removed:
COLLATE BINARY, the TEXT-affinity check, the encoding check, the all_varchar check, and in-scan evaluation.