Targeted queries over compressed SQLiteΒΆ

Upnaam can query a gzip-compressed SQLite database without writing the full decompressed database to disk. This matters for the Bihar ration source: its two archive parts occupy about 3.30 GB, while the logical SQLite database is 56,741,351,424 bytes.

The generic adapter treats ordered archive parts as one compressed byte stream, builds an indexed-gzip seek index, and exposes decompressed byte ranges to SQLite through a read-only APSW virtual file system. The index is built once and reused. For the Bihar source it is 417,660,907 bytes, or about 398 MiB.

Install the optional dependencies:

pip install "upnaam[compressed-sqlite]"

Then issue ordinary targeted SQL:

from pathlib import Path

from upnaam.compressed_sqlite import open_gzip_sqlite

parts = [
    Path("ration_cards.sqlite.gz.001"),
    Path("ration_cards.sqlite.gz.002"),
]
index = Path("ration_cards.sqlite.gzidx")

with open_gzip_sqlite(parts, index) as connection:
    rows = connection.execute(
        "SELECT id, members_qty, sub_table FROM family_members_tables WHERE id = ?",
        ("00000001",),
    ).fetchall()

The connection is always read-only. Each index has a JSON sidecar recording the ordered source-part hashes, decompressed size, index hash, and implementation revision. Upnaam refuses to use a stale, partial, or unverified index. Pass rebuild_index=True only when deliberately replacing the index after a source change.

This mechanism makes indexed point lookups practical. The Bihar database has primary-key indexes on family_members_tables.id and ration_card_details.ration_card_number; queries on those keys are targeted lookups. It does not make an unindexed predicate cheap: a filter such as ration_card_details.village_id = ? still scans that table. Nor does the adapter alter the data or turn the ration transcription into a surname label. Source-specific name selection remains a separate pipeline stage.