Hide pgsqlite internal objects from client sqlite_master queries (result filtering)#83
Open
robertjbass wants to merge 1 commit into
Open
Hide pgsqlite internal objects from client sqlite_master queries (result filtering)#83robertjbass wants to merge 1 commit into
robertjbass wants to merge 1 commit into
Conversation
…ltering A client-issued sqlite_master / sqlite_schema SELECT should not expose pgsqlite's internal objects: the __pgsqlite_* bookkeeping tables, the pg_catalog tables/views pgsqlite materializes as real SQLite objects, or the indexes/triggers owned by them. Rather than rewriting the query text (which can corrupt complex predicates such as a large NOT IN list or an ESCAPE clause), the catalog interceptor now runs the client's ORIGINAL, UNMODIFIED query and filters pgsqlite-internal rows out of the result. Because the query text is never changed, no client query can be corrupted by this path. A small probe of sqlite_master builds the authoritative set of internal object names (including internal-owned indexes/triggers whose own names are not reserved) so they are hidden even when the client projects only the name column. The reserved pg_catalog sets are exact-name (never a pg_% wildcard) so a user-owned object like pg_indexes or pg_my_report is preserved. A projection with no name/tbl_name column (e.g. SELECT sql FROM sqlite_master) is returned unfiltered, and any unrecognized query shape fails open and runs unmodified. Covered by unit tests for detection/filtering and wire-level integration tests, including a large non-matching NOT IN list that proves the client's query is not corrupted.
This was referenced Jul 11, 2026
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.
Problem
Client
sqlite_master/sqlite_schemaqueries return pgsqlite's own internal objects alongside the user's tables: the__pgsqlite_*bookkeeping tables, the materialized pg_catalog tables (pg_attrdef,pg_constraint,pg_depend,pg_index), the materialized pg_catalog / information_schema views, and internal indexes on them. These leak into schema browsers, ORMs, and\dt-style tooling connected over the wire.Approach: filter results, do not rewrite the query
This hides those internal objects by filtering the result rows, never by modifying the client's SQL. When
intercept_querysees a single plain SELECT whose FROM referencessqlite_master/sqlite_schema, it:SELECT name, tbl_name FROM sqlite_masterprobe (so internal-owned indexes/triggers are caught bytbl_nameeven when the client only projectsname),name(or projectedtbl_name) is an internal object:__pgsqlite_%prefix, the reserved pg_catalog table/view names (exact-name set, never apg_%wildcard, so a user's ownpg_myreportsurvives), or in the probe-derived denylist.Because the query text is never altered, this cannot corrupt a query (an earlier query-rewriting attempt broke complex predicates - large
NOT INlists,ESCAPEclauses). Fail-open: any unrecognized shape (subquery-wrapped FROM, set ops, noname/tbl_nameprojection such asSELECT sqlorSELECT count(*), or a parse failure) returns the original result unchanged.Boundary
A query whose text itself trips an earlier catalog-interceptor branch (e.g. one embedding many
pg_*names) is handled by that branch before this one and is out of scope here. SimpleSELECT * FROM sqlite_masterfrom external tools is handled cleanly.Tests
Wire-level integration tests plus unit tests: internal tables/views/indexes hidden from
SELECT *,type='table',type='index',type='view'scans; user tables/views/indexes returned; a userpg_myreportreturned; a large non-pgNOT IN+ESCAPEreturns correct rows (no corruption);SELECT sql FROM sqlite_masterreturned unfiltered. Verified against real psql.