firebird

Föderierter Nur-Lese-Zugriff auf Firebird-Datenbanken (3.0/4.0/5.0) aus DuckDB, mit Projektions- und Filter-Pushdown, Unterstützung für INT128 / DECIMAL(38) / TIMESTAMP_TZ, nativem ATTACH und Behandlung von CHARACTER SET NONE (Standard win1252; außerdem strict / iso8859_1 / blob) mit korrektem Filter-Pushdown auf transkodierten Spalten.

Maintainer: flozer

Installation und Laden

INSTALL firebird FROM community;
LOAD firebird;

Beispiel

LOAD firebird;
-- 1. Live scan against a Firebird server.
SELECT * FROM firebird_scan(
'firebird://APP_READONLY:secret@db.host:3050/srv:/data/prod.fdb?charset=UTF8',
'EMPLOYEE') LIMIT 10;
-- 2. Projection + filter pushdown — only EMP_NO, FIRST_NAME and the
-- WHERE predicate are sent to Firebird.
SELECT EMP_NO, FIRST_NAME
FROM firebird_scan('firebird://…', 'EMPLOYEE')
WHERE DEPT_NO = '600'
AND HIRE_DATE > DATE '2020-01-01';
-- 3. Discover the schema.
SELECT * FROM firebird_tables('firebird://…');
-- 4. Native ATTACH — every Firebird table reachable through DuckDB's catalog.
ATTACH 'firebird://APP_READONLY:secret@host/path/db.fdb' AS fb (TYPE firebird);
SELECT * FROM fb.main.EMPLOYEE WHERE DEPT_NO = '600';
-- 5. Firebird-native diagnostics (v0.6).
SELECT * FROM firebird_profile_table('fb.main.EMPLOYEE');
SELECT * FROM firebird_pool_stats('fb');
-- 6. Federated JOIN — Firebird ⋈ Parquet.
SELECT e.dept_no, COUNT(*), AVG(e.salary)
FROM firebird_scan('firebird://…', 'EMPLOYEE') e
JOIN read_parquet('s3://lake/departments/*.parquet') d
ON e.dept_no = d.dept_no
GROUP BY e.dept_no;
-- 7. Legacy database declared CHARACTER SET NONE. Firebird does
-- NOT transliterate NONE columns to UTF-8 on the wire; pick
-- the encoding the writing application used.
SELECT * FROM firebird_scan(
'C:/legacy/company.fdb',
'TABENTRADASAIDA',
none_encoding='win1252');

Über firebird

duckdb-firebird stellt Firebird-Tabellen als DuckDB-Tabellen bereit; der DuckDB-Optimierer reicht Projektions- und Filterprädikate an den Firebird-Server weiter. Große Aggregationen laufen weiterhin in DuckDBs vektorisiertem Executor; Sie müssen nur keine parallele ETL- Pipeline mehr pflegen, um Firebird-Daten zuerst nach Parquet zu exportieren.

Oberfläche

  • firebird_scan(conn, table [, named params]) — Scan einer einzelnen Tabelle mit Projektions- und Filter-Pushdown und optionalem parallelem PK-Bereichsscan.
  • firebird_tables(conn) — listet Benutzertabellen (und Sichten, externe Tabellen, GTTs) mit PK-Informationen auf.
  • firebird_attach_sql(conn[, schema]) — gibt das DDL für ein leichtgewichtiges, sichtbasiertes Attach aus, wenn Sie nicht die volle Lebensdauer der StorageExtension wollen.
  • ATTACH 'firebird://…' AS fb (TYPE firebird) — nativer schreibgeschützter Katalog mit SELECT * FROM fb.main.TABLE, föderierten Joins, DESCRIBE, groß-/kleinschreibungsunabhängiger Suche und Connection Pooling.
  • firebird_profile_table('fb.main.TABLE') — faktische Diagnostik v0.6 zu PKs, Indizes, Filter-/Wasserzeichen-Kandidaten, Sicht-Risiko und empfohlenen Partitionen.
  • firebird_pool_stats('fb') — Connection-Pool-Zähler v0.6 für einen angehängten Firebird-Katalog.

Pushdown

  • Projektion: nur angeforderte Spalten gehen über die Leitung.
  • Filter: =, <>, <, >, <=, >=, IS [NOT] NULL, BETWEEN, IN, AND/OR, LIKE 'prefix%' werden in Firebird-SQL übersetzt. Alles andere bleibt in DuckDB oberhalb des Scans.
  • Paralleler PK-Bereichsscan: Opt-in über den benannten Parameter partitions=N — empfohlen für entfernte / Classic-Firebird-Server, bei denen Parallelität günstig ist.
  • Manuelles row_limit=N: gibt Firebirds ROWS N direkt aus.

Typabbildung

Kompatibilität mit Firebird-3-+-4-+-5-Servern:

  • INTEGER, BIGINT, SMALLINT, CHAR(N), VARCHAR(N), NUMERIC/DECIMAL(p, s) (bis 38 Stellen), FLOAT, DOUBLE, DATE, TIME, TIMESTAMP, BOOLEAN — exakte Abbildung.
  • INT128HUGEINT; DECIMAL(p > 18, s)DECIMAL(38, s).
  • TIMESTAMP WITH TIME ZONE (einschließlich der erweiterten TZ-Form von FB4) → DuckDB TIMESTAMP WITH TIME ZONE (UTC-Zeitpunkt bleibt erhalten).
  • TIME WITH TIME ZONE → DuckDB TIME WITH TIME ZONE.
  • BLOB SUB_TYPE 1 (Text) → VARCHAR; andere BLOBs → BLOB.
  • DECFLOAT(16) / DECFLOAT(34) → verlustfreies VARCHAR über serverseitiges CAST(... AS VARCHAR(64)) (v0.6).

Verbindungszeichenfolgen

firebird://USER:PASS@HOST:PORT/DB_PATH?charset=UTF8&dialect=3&role=…
user=APP_READONLY;password=secret;database=server:/data/db.fdb;charset=UTF8

Ein bloßer Pfad (/var/lib/firebird/test.fdb, C:/data/prod.fdb) wird für lokale Datenbanken ebenfalls akzeptiert.

Benutzer / Passwort / Zeichensatz / Rolle / Dialekt / Partitionen / row_limit können zur Aufrufzeit über benannte Parameter überschrieben werden.

Zeichensatzbehandlung

DuckDB speichert Zeichenketten intern als UTF-8. Die Erweiterung akzeptiert für den Client-Zeichensatz nur UTF8, UTF-8, NONE oder OCTETS; alles andere wird zur Bind-Zeit zurückgewiesen.

Datenbanken mit einem echten Zeichensatz (WIN1252, ISO8859_1, UTF8, …) durchlaufen den Roundtrip unter dem Standard charset=UTF8 sauber: Firebird transliteriert serverseitig, sodass São Paulo, Açúcar, Coração ohne Extra-Konfiguration als gültiges UTF-8 ankommen.

Datenbanken (oder einzelne Spalten) mit CHARACTER SET NONE sind anders: Firebird liefert die Rohbytes zurück, die die schreibende Anwendung gespeichert hat, ohne Transliteration. Der Standardmodus win1252 der Erweiterung dekodiert die Bytes, die viele ältere brasilianische und westeuropäische ERP-Systeme verwenden. Der Aufrufer kann weiterhin die Kodierung wählen, die die Quellanwendung verwendet hat:

  • none_encoding='win1252' (Standard) — Bytes als Windows-1252 → UTF-8 dekodieren.
  • none_encoding='strict' — nur gültiges UTF-8 akzeptieren.
  • none_encoding='iso8859_1' (Alias 'latin1') — Bytes als ISO-8859-1 → UTF-8 dekodieren.
  • none_encoding='blob' — NONE-Textspalten als DuckDB-BLOB (Rohbytes) bereitstellen.

Die Option wird sowohl von firebird_scan(…) als auch von der Form ATTACH ... (TYPE firebird, none_encoding 'win1252') akzeptiert. Solange none_encoding != 'strict', ist Filter-Pushdown auf NONE-Textspalten bewusst deaktiviert — das SQL-Literal, das wir senden würden, ist UTF-8 und würde serverseitig nicht zu den Rohbytes passen. DuckDB wendet den Textfilter nach der Transkodierung oberhalb des Scans an.

Verifiziert gegen

  • Firebird 3.0 (apt firebird3.0-server, CI-Fixture)
  • Firebird 4.0.x (firebirdsql/firebird:4-noble)
  • Firebird 5.0.4 (Windows lokal + firebirdsql/firebird:5-noble)
  • DuckDB v1.5.3 - v1.5.5 (StorageExtension::Register-API)

Hinzugefügte Funktionen

function_name function_type description comment examples
firebird_attach_sql table NULL NULL
firebird_comments table NULL NULL
firebird_computed_columns table NULL NULL
firebird_dependencies table NULL NULL
firebird_domains table NULL NULL
firebird_explain_pushdown table NULL NULL
firebird_foreign_keys table NULL NULL
firebird_generate_dbt_sources table NULL NULL
firebird_generators table NULL NULL
firebird_health table NULL NULL
firebird_index_profile table NULL NULL
firebird_indexes table NULL NULL
firebird_last_query table NULL NULL
firebird_pool_stats table NULL NULL
firebird_profile_table table NULL NULL
firebird_query_log table NULL NULL
firebird_scan table NULL NULL
firebird_tables table NULL NULL
firebird_type_audit table NULL NULL

Überladene Funktionen

Diese Erweiterung fügt keine Funktionsüberladungen hinzu.

Hinzugefügte Typen

Diese Erweiterung fügt keine Typen hinzu.

Hinzugefügte Einstellungen

name description input_type scope aliases
firebird_pool_enabled Enable the per-ATTACH FirebirdConnectionPool. When false, every Acquire opens a fresh connection and Release destroys it. BOOLEAN GLOBAL []
firebird_pool_idle_timeout_ms How long (in milliseconds) a released connection may sit in the idle queue before it is discarded on the next Acquire. 0 = no expiry (default). Clock starts at Release(). BIGINT GLOBAL []
firebird_pool_max_size Maximum number of idle connections kept in the pool. 0 = unlimited (default). Caps the idle queue, not active leases. BIGINT GLOBAL []
firebird_query_log_size Maximum entries kept by firebird_query_log() per session. 0 disables the log (default). BIGINT GLOBAL []