ODBC Stack Modernization
This is a proposed Change for Fedora Linux.
This document represents a proposed Change. As part of the Changes process, proposals are publicly announced in order to receive community feedback. This proposal will only be implemented if approved by the Fedora Engineering Steering Committee.
Summary
Modernize the Fedora ODBC stack across 7 packages (unixODBC and 6 driver packages: mariadb-connector-odbc, mysql-connector-odbc, postgresql-odbc, freetds, sqliteodbc, mdbtools). The central change is replacing the static, centrally-maintained /etc/odbcinst.ini driver registration file with an auto-generated configuration assembled from per-driver drop-in snippets, using RPM file triggers — the same pattern used by ldconfig, ca-certificates, and crypto-policies. Supporting changes include switching to bare library names resolved via a compiled-in search path, moving driver plugins to a dedicated directory, and general spec cleanups.
Owner
- Name: Michal Schorm
- Email: mschorm@redhat.com
Proposed code changes
All changes are in the dropin-registration topic branches in the Chnage owner’s forks:
-
unixODBC — drop-in infrastructure, file triggers,
%ghostconfig, migration scriptlets, manual page for the new script -
mariadb-connector-odbc — ship
10-mariadb.inidrop-in snippet -
mysql-connector-odbc — ship
10-mysql.inidrop-in snippet -
postgresql-odbc — ship
10-postgresql.inidrop-in snippet -
freetds — ship
10-freetds.inidrop-in snippet -
sqliteodbc — ship
10-sqlite.inidrop-in snippet, remove legacyodbcinstscriptlets -
mdbtools — ship
10-mdbtools.inidrop-in snippet
Detailed Description
Background
The ODBC driver manager (unixODBC) uses /etc/odbcinst.ini to map driver names to shared libraries. In Fedora, this file has historically been shipped as %config(noreplace) inside the unixODBC package, pre-populated with entries for all known Fedora ODBC drivers.
The driver entries in Fedora were in poor shape. FileUsage values were wrong for multiple drivers, library paths were hardcoded and multilib-unfriendly, and the FreeTDS entry contained a dead Port key that the driver never reads from odbcinst.ini. These problems persisted because driver entries lived in the wrong package — fixing a driver’s registration required a change to unixODBC, not to the driver package itself.
This coupling created several structural problems:
-
Wrong ownership: Driver packages had no control over their own registration. A driver maintainer who wanted to fix or update their entry had to coordinate a change in
unixODBC. - Stale entries: All known drivers were pre-populated in the config regardless of whether they were installed, leading to broken references.
-
Invisible drivers: New driver packages (e.g.
mdbtools-odbc) were not registered at all until someone manually added them to theunixODBCspec.mdbtools-odbcwas invisible to ODBC applications after install. -
Fragile upgrades: The
%config(noreplace)semantics mean RPM silently keeps the old file on upgrade, so corrections (like fixedFileUsagevalues) never reach existing installations.
Of all 6 driver packages in Fedora, only sqliteodbc attempted self-registration via %post/%preun scriptlets calling odbcinst -i/odbcinst -u. The other 5 relied entirely on unixODBC pre-populating their entries.
What is changing
The modernization consists of two groups of changes:
Already in Fedora Rawhide (foundation work):
- ODBC driver plugins moved from
%{_libdir}to a dedicated%{_libdir}/odbc/directory across all driver packages. -
unixODBCcompiled with--with-odbc-driver-path=%{_libdir}/odbc, enabling bare library names (e.g.Driver = libmaodbc.soinstead of full paths). -
FileUsagevalues corrected across all drivers (BZ#2453060). -
Suggests:added for all 6 ODBC driver packages. - Removal of a 17-year-old dead patch (
keep-typedefs.patch).
Proposed in this change (driver registration):
- Each driver package ships a static
.inisnippet file to/usr/lib/odbc/odbcinst.d/(vendor defaults). -
unixODBCowns%transfiletriggerinand%transfiletriggerpostunscriptlets that run a regeneration script (odbcinst-generate) whenever snippets are installed or removed. - The regeneration script merges all snippets (vendor defaults overlaid by admin overrides) and atomically replaces
/etc/odbcinst.ini. -
/etc/odbcinst.inichanges from%config(noreplace)to%ghost— RPM tracks ownership but the file is never shipped; it is always generated. - Administrators can override or disable vendor drivers via
/etc/odbc/odbcinst.d/(see below).
Drop-in directory layout
/usr/lib/odbc/odbcinst.d/ ← vendor snippets (shipped by driver RPMs) 10-mariadb.ini 10-mysql.ini 10-postgresql.ini 10-freetds.ini 10-sqlite.ini 10-mdbtools.ini /etc/odbc/odbcinst.d/ ← admin overrides and additions /etc/odbcinst.ini ← generated output (%ghost)
Override semantics:
- Files are named
NN-name.ini. The numeric prefix controls merge order. - Vendor range: 10–49. Admin range: 50–99.
- When two files share the same name after stripping the prefix (e.g.
10-mariadb.iniand60-mariadb.ini), the higher-numbered one wins. - To disable a vendor driver, symlink its snippet to
/dev/null:
ln -sf /dev/null /etc/odbc/odbcinst.d/10-freetds.ini
- To apply changes after editing drop-in files manually, run:
odbcinst-generate
These semantics follow the established systemd convention used throughout Fedora.
Precedent
This is the standard Fedora pattern for generated configuration. At least 22 packages use the same %transfiletriggerin + regeneration model, including:
-
glibc-common—/etc/ld.so.conf.d/→ldconfig→/etc/ld.so.cache -
ca-certificates—/etc/pki/ca-trust/source/→update-ca-trust→ca-bundle.crt -
crypto-policies—/usr/share/crypto-policies/→update-crypto-policies -
fontconfig—/usr/share/fonts/→fc-cache -
shared-mime-info—/usr/share/mime/→update-mime-database -
glib2—/usr/share/glib-2.0/schemas/→glib-compile-schemas
Migration strategy (for FESCo consideration)
This is the area where community input is most welcome.
When upgrading from a system where /etc/odbcinst.ini was %config(noreplace) to the new %ghost model, RPM does not automatically create an .rpmsave backup. Without intervention, any user modifications to odbcinst.ini would be silently lost.
The proposed migration strategy:
- A
%pretransLua scriptlet inunixODBCdetects first-time upgrades (the drop-in directory does not yet exist) and renames/etc/odbcinst.inito/etc/odbcinst.ini.rpmsave. On subsequent upgrades (drop-in directory already exists), the%pretransis a no-op. -
%postchecks whether/etc/odbcinst.ini.rpmsaveexists. If so, it prints a notice to stderr explaining that driver registration has moved to drop-in snippets, pointing users to the.rpmsavefile and explaining how to migrate custom entries. This notice is repeated on every upgrade as long as the.rpmsavefile remains, serving as a persistent reminder until the user completes the migration and removes it.
What users need to do:
- Users who never modified
odbcinst.ini: nothing. All standard drivers are registered automatically via snippets. - Users who added custom driver entries: copy their custom
[sections]fromodbcinst.ini.rpmsaveinto a new file under/etc/odbc/odbcinst.d/and runodbcinst-generate.
Alternatives considered:
- Content-based detection (parse the file to detect user modifications): rejected as unreliable in RPM’s limited Lua environment.
-
Always preserve (never create
.rpmsave): rejected because it leaves the old static file alongside the new generated one, causing confusion. - In-place migration (automatically convert user entries to drop-in files): rejected as too complex and opaque. Users should be aware of the new mechanism.
Rejected ideas: scriptlet-based registration (Debian/Ubuntu, openSUSE)
Other distributions use odbcinst -i/odbcinst -u commands in driver package scriptlets (postinst/postrm on Debian, %post/%preun on openSUSE). I considered and rejected this for Fedora due to various bugs present in this approach.
How it works in Debian/Ubuntu: Each driver package calls odbcinst -i -d -f /usr/share/<driver>/odbcinst.ini.template in its postinst and odbcinst -u -d in its postrm. This approach has generated real bugs over more than a decade:
-
Ubuntu Bug #1173083:
tdsodbcused a debconf prompt to ask whether to register the driver. In automated installs (containers, CI, preseed), the question was never answered, leaving FreeTDS silently unregistered. Open for 12 years before being fixed. -
Debian Bug #1001141:
odbc-mariadbcalledodbcinstin its maintainer scripts but did not declare a dependency on theodbcinstbinary, causing silent registration failures.
How it works in openSUSE: Similar, using RPM %post/%preun scriptlets. All errors are suppressed with > /dev/null 2>&1 || true, so failures are completely silent. Coverage is inconsistent: only 3 of 5 driver packages self-register; mariadb-connector-odbc ships a sample .ini but no scriptlets; mdbtools has its ODBC driver incorrectly placed in the -devel subpackage.
Why the scriptlet approach is fundamentally fragile:
-
Race conditions:
odbcinstperforms a read-modify-write cycle on/etc/odbcinst.iniwithout file locking. If two driver packages run scriptlets concurrently, the file can be corrupted or one registration silently lost. -
Reference counting:
odbcinstmaintains a reference count per driver entry. A failed or interrupted scriptlet can leave the count out of sync, resulting in stale entries that never get removed or premature removal of valid entries. -
Cross-package file modification: Multiple independent packages all modify a file owned by
unixODBC, violating single file ownership. - Per-driver boilerplate: Every driver package must independently implement registration logic, template files, and correct dependency declarations. Each one is a potential source of bugs.
Why the drop-in approach is better: RPM file triggers (%transfiletriggerin) are transactional — they fire once after the entire transaction completes, not once per package. The regeneration script rebuilds /etc/odbcinst.ini from scratch using only the snippet files currently on disk. There is no read-modify-write race, no reference counting, no possibility of stale entries, and driver packages need zero scriptlet logic — they ship a static file and nothing else.
With this change, Fedora would be the first distribution with a systemic, race-free, declarative ODBC driver registration mechanism with first-class admin override semantics.
Feedback
Benefit to Fedora
-
Decoupled driver registration: Each driver package owns its own registration. Adding a new ODBC driver to Fedora no longer requires changes to
unixODBC. -
Correct out-of-the-box experience: Only installed drivers appear in the config. Installing a driver automatically makes it visible to applications; removing it automatically cleans up. This fixes the long-standing problem where
mdbtools-odbcwas installable but invisible to ODBC applications. - Admin override mechanism: System administrators can override vendor defaults or disable drivers without editing generated files, using the same drop-in pattern familiar from systemd, ldconfig, and crypto-policies.
-
Bare library names: Driver entries use plain library names (e.g.
Driver = libmaodbc.so) resolved via a compiled-in search path, eliminating hardcoded%{_libdir}paths and multilib ambiguity. -
Correct metadata:
FileUsagevalues are fixed across all drivers. Fedora becomes the first distribution to ship correct values for all its ODBC drivers. -
Reduced spec complexity: Driver packages no longer need
%post/%preunscriptlets for registration. A single static.inifile per driver replaces all of it.
Scope
-
Proposal owners:
- Implement drop-in infrastructure in
unixODBC(directories, regeneration script, file triggers,%ghostconfig, migration scriptlets) - Add drop-in snippet files to all 6 driver packages:
mariadb-connector-odbc,mysql-connector-odbc,postgresql-odbc,freetds,sqliteodbc,mdbtools - Remove legacy
%post/%preunodbcinstscriptlets fromsqliteodbc - Test upgrade scenarios in containers via COPR
- Implement drop-in infrastructure in
-
Other developers:
- No action required from other package maintainers. The change is self-contained within the 7 packages listed above.
-
Release engineering: N/A (not a System Wide Change)
-
Policies and guidelines: N/A
-
Trademark approval: N/A
-
Alignment with the Fedora Strategy: Fedora leads in the Linux distribution development. This change adopts a modern, well-established Fedora pattern for an area of the stack that has lagged behind.
Upgrade/compatibility impact
On upgrade from a previous Fedora release:
-
/etc/odbcinst.iniis saved as/etc/odbcinst.ini.rpmsave. - A new
/etc/odbcinst.iniis generated from drop-in snippets. - All standard drivers (MariaDB, MySQL, PostgreSQL, FreeTDS, SQLite, MDBTools) are registered automatically if their packages are installed.
- Users with custom driver entries in the old
odbcinst.inineed to migrate them to drop-in snippet files under/etc/odbc/odbcinst.d/. A notice is printed during upgrade with instructions.
Applications using ODBC continue to work without changes. The generated odbcinst.ini uses the same INI format as before; only the mechanism that produces it has changed.
How To Test
Test builds are available in COPR: mschorm/ODBC
Fresh install (no previous ODBC config):
- Install
unixODBCand one or more driver packages - Verify
/etc/odbcinst.iniis generated and contains entries for the installed drivers - Verify that uninstalling a driver package removes its entry from
odbcinst.ini
Upgrade from current Rawhide (unmodified config):
- Start with a system running the current
unixODBC(pre-drop-in) - Upgrade to the new version
- Verify
/etc/odbcinst.ini.rpmsaveis created - Verify the new
/etc/odbcinst.inicontains correct entries for installed drivers
Upgrade with custom driver entries:
- Start with a system where
/etc/odbcinst.inihas been manually edited (e.g. a custom[MyDriver]section added) - Upgrade to the new version
- Verify
/etc/odbcinst.ini.rpmsavepreserves the custom entries - Copy the custom section into
/etc/odbc/odbcinst.d/60-mydriver.ini - Run
odbcinst-generate - Verify the custom driver appears in the regenerated
/etc/odbcinst.ini
Admin override:
- Install
mariadb-connector-odbc(ships10-mariadb.ini) - Create
/etc/odbc/odbcinst.d/60-mariadb.iniwith modified settings - Run
odbcinst-generate - Verify the admin override takes precedence
Driver disable:
ln -sf /dev/null /etc/odbc/odbcinst.d/10-freetds.ini- Run
odbcinst-generate - Verify FreeTDS no longer appears in
/etc/odbcinst.ini
User Experience
For most users, the change is invisible. Installing an ODBC driver package automatically registers it; removing it automatically unregisters it. No manual odbcinst commands are needed.
Power users and administrators gain a familiar drop-in override mechanism. Customizing ODBC driver registration now works the same way as customizing library paths (ld.so.conf.d) or CA certificates (ca-trust).
Users upgrading from a previous Fedora release who had custom entries in odbcinst.ini will see a migration notice on each upgrade until they complete the migration and remove the .rpmsave file.
Dependencies
All 7 affected packages are maintained by the change owner:
unixODBCmariadb-connector-odbcmysql-connector-odbcpostgresql-odbcfreetdssqliteodbcmdbtools
No other packages are affected. The generated /etc/odbcinst.ini is format-compatible with the previous static file.
Contingency Plan
- Contingency mechanism: Revert the
unixODBCspec to ship a static%config(noreplace)odbcinst.iniand remove drop-in snippet files from driver packages. This is a straightforward revert of the topic branch in each package. - Contingency deadline: N/A (not a System Wide Change)
- Blocks release? No
Documentation
- BZ#2453060 — Standardize unixODBC connector installation directory
- COPR test repository: mschorm/ODBC
- A new
odbcinst-generate(1)man page will be shipped with theunixODBCpackage, documenting the regeneration tool, drop-in directory layout, and override semantics - The existing upstream
odbcinst.ini(5)man page will be updated or supplemented with a note about the drop-in mechanism
Release Notes
The ODBC driver stack has been modernized. ODBC driver registration now uses a drop-in snippet mechanism: each driver package ships a small .ini file that is automatically merged into /etc/odbcinst.ini when the package is installed or removed. Administrators can override vendor defaults or add custom drivers by placing files in /etc/odbc/odbcinst.d/.
Users who had custom entries in /etc/odbcinst.ini will find their previous configuration saved as /etc/odbcinst.ini.rpmsave after upgrading. Custom driver sections should be migrated to individual files under /etc/odbc/odbcinst.d/.
Last edited by @amoloney 2026-07-13T17:10:02Z
Last edited by @amoloney 2026-07-13T17:10:02Z