NAME
DBIO::Firebird::Storage::ODBC - Driver for the Firebird RDBMS via DBD::ODBC
VERSION
version 0.900004
DESCRIPTION
Firebird reached through DBD::ODBC rather than through DBD::Firebird or DBD::InterBase. The engine semantics come from DBIO::Firebird::Storage::Common and the ODBC transport helpers from DBIO::Storage::DBI::ODBC; this class holds only what is true of this transport and of no other (ADR 0010).
The nested-statement-handles-across-commits problem of the two native drivers is a fact of their DBDs (connect_call_use_softcommit, disable_sth_caching); this class has not been checked against it (see "CAVEATS").
Why this class is not a subclass of the InterBase driver
DBIO::Firebird::Storage::InterBase speaks the ib_* API of DBD::InterBase -- ib_dialect in the DSN, ib_softcommit, ib_time_all, and $sth->func('ib_plan') for a query plan. None of it exists on DBD::ODBC, so inheriting from that class would put four connection-time attribute writes and one private XSUB call into a handle that has never heard of any of them. The split is the one ADR 0001 already draws and this class extends sideways: what is a fact about the SQL both engines speak lives on Storage::Common and is inherited here (the FIRST/SKIP limit dialect, RAND(), GEN_ID sequences, RDB$DATABASE in the EXISTS query, the refusal of the four set operations Firebird has no operator for, INSERT ... RETURNING, the " quote char, sqlt_type); what hangs off a DBD's own API stays with that DBD.
The same cut decides what an DBIO::AccessBroker may hand this transport: an odbc_ attribute in its hash answer or beside it goes to DBI->connect, an ib_ one is refused, since DBD::ODBC would keep it without applying it ("ib_ attributes through an AccessBroker" in DBIO::Firebird::Storage::InterBase).
Query plans are not reachable over ODBC
Firebird has no EXPLAIN statement of any kind, and its plan is an attribute of the prepared statement, read with isc_dsql_sql_info(isc_info_sql_get_plan). The two native DBDs expose that call as $sth->func('ib_plan'); DBD::ODBC exposes nothing equivalent, and the ODBC API has no vendor-neutral spelling for it either. _explain_query therefore throws here rather than inheriting either half of a wrong answer: core's EXPLAIN <query> would be a Token unknown parse error from the server, and the ib_plan override of DBIO::Firebird::Storage::InterBase would be a call into a function this handle does not have. Connect through DBD::Firebird or DBD::InterBase when you need a plan.
Which storage class an ODBC DSN lands in
The one this schema declares. An ODBC DSN does not say which engine is behind it -- every engine reached through DBD::ODBC shares the DBD name ODBC -- so nothing picks this class from the DSN: it is reached by declaring it, on the schema class or on a clone of it before connecting:
package MyApp::DB;
use base 'DBIO::Schema';
__PACKAGE__->storage_type('+DBIO::Firebird::Storage::ODBC');
# or, for a schema class shared between transports
my $schema = MyApp::DB->clone(storage_type => '+DBIO::Firebird::Storage::ODBC')
->connect('dbi:ODBC:Driver=Firebird;Dbname=/path/app.fdb', $user, $pass);
The declared storage class stands (DBIO core ADR 0059): the storage stays in this class, and driver resolution adds nothing to the connect string.
The Firebird component and the -fb shortcut declare DBIO::Firebird::Storage, the DBD::Firebird class. An ODBC DSN under that declaration does not reach this class: the storage stays DBIO::Firebird::Storage, core warns about the driver mismatch, and that class appends ib_dialect=3 to the ODBC connect string. A schema that loads the component with load_components('Firebird') cannot declare this class on a clone either, since the component sets its storage class on every connection. Letting the Firebird driver adapt itself to an ODBC DSN (_adapt_to_access_path, ADR 0059) is open.
DBIO core ADR 0067: a schema always declares its driver; nothing detects it from the connected handle.
METHODS
connect_call_datetime_setup
Used as:
on_connect_call => 'datetime_setup'
A noop on this transport, so that the same connect_info works for all three Firebird DBDs. The native drivers need "connect_call_datetime_setup" in DBIO::Firebird::Storage::InterBase to put DBD::InterBase into ISO date and timestamp formats (ib_time_all); the ODBC driver already answers in the ODBC canonical form, which is the same %Y-%m-%d %H:%M:%S shape DBIO::Firebird::DateTime::Format parses.
Without this method the connect-call would die looking for it -- datetime_setup is resolved by name against the storage class.
The native storages put every connection into the ISO formats by default; this transport needs nothing analogous, because the ODBC driver already answers in the canonical form. That is the reading of the existing claim above, not something measured here: no Firebird ODBC driver was available to test against, so the transport is unchanged.
CAVEATS
Unverified. No Firebird server was reached over ODBC for any of this. The two savepoint workarounds and the
OdbcFbarray-operations one are upstream DBIx::Class findings carried over with their reasons; the datetime claim above is the ODBC canonical format rather than something observed. The ODBC leg of t/10-firebird.t, t/20-firebird-core.t and t/30-datetime-firebird.t (DBIO_TEST_FIREBIRD_ODBC_DSN) is where a server checks them.Query plans are unavailable, see "Query plans are not reachable over ODBC".
SEE ALSO
DBIO::Firebird - Firebird schema component
DBIO::Firebird::Storage::Common - Shared Firebird/InterBase logic
DBIO::Firebird::Storage - Firebird driver via DBD::Firebird
DBIO::Firebird::Storage::InterBase - InterBase driver via DBD::InterBase
DBIO::Storage::DBI::ODBC - Base class for ODBC drivers
AUTHOR
DBIO & DBIx::Class Authors
COPYRIGHT AND LICENSE
Copyright (C) 2026 DBIO Authors Portions Copyright (C) 2005-2025 DBIx::Class Authors Based on DBIx::Class, heavily modified.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.