Jump to content

Extension:ODBC

From mediawiki.org
MediaWiki extensions manual
ODBC
Release status: stable
Implementation Parser function , Special page
Description Generic ODBC database connectivity for MediaWiki. Query any ODBC-accessible database directly from wiki pages using five parser functions, with prepared statement support, SQL injection protection, an admin interface for connection testing and table browsing, optional result caching, and seamless integration with the External Data extension.
Author(s) Paul Vodrazka
Latest version 1.5.0 (2026-03-03)
MediaWiki >= 1.39.0
PHP >= 7.4.0
Database changes No
  • $wgODBCSources
  • $wgODBCAllowArbitraryQueries
  • $wgODBCMaxRows
  • $wgODBCQueryTimeout
  • $wgODBCCacheExpiry
  • $wgODBCExternalDataIntegration
  • $wgODBCMaxQueriesPerPage
  • $wgODBCSlowQueryThreshold
  • $wgODBCMaxConnections
  • ‎<database>
  • ‎<ODBC>
  • ‎<SQL>
  • ‎<data integration>
  • ‎<parser function>
  • ‎<external data>
  • odbc-query
  • odbc-admin
Licence GNU General Public License 2.0 or later
Download
README
CHANGELOG

The ODBC extension provides generic ODBC database connectivity for MediaWiki. It enables wiki editors to query any database that has an ODBC driver — including Microsoft SQL Server, MySQL, PostgreSQL, Oracle, IBM DB2, Microsoft Access, SQLite, SAP HANA, Snowflake, and Amazon Redshift — directly from wiki pages using parser functions.

All queries are executed read-only, with multi-layered SQL injection protection. Results are stored in page-scoped variables and rendered using inline wikitext templates or wiki templates.

Why ODBC?

[edit]
  • Universal Database Access: One extension connects MediaWiki to any ODBC-accessible database — no vendor-specific extensions required.
  • Secure by Default: Prepared statements, SQL pattern blocklists, identifier validation, and read-only enforcement prevent SQL injection by design.
  • Flexible: Five parser functions cover single-value lookups, tabular display, and template-driven rendering.
  • External Data Compatible: Registers an odbc_generic connector for the External Data extension, extending its ecosystem to ODBC sources.

Use Cases

[edit]
Use Case Example Features Used
Business Dashboards Display KPIs, sales figures, or inventory counts from a SQL Server data warehouse #odbc_query with prepared statements, #odbc_value for single metrics
Employee Directories Searchable staff listings from an HR database Prepared statements with parameters, #display_odbc_table with a wiki template
Product Catalogues Render product tables from a MySQL database Composed queries, #for_odbc_table for inline wikitable rows
Report Archives Surface historical data from a legacy Access or DB2 database DSN-based connections, query caching for performance
IT Asset Tracking List servers, licenses, or configurations from a CMDB Special:ODBCAdmin for ad-hoc exploration, prepared statements for wiki pages
Data Integration Combine ODBC data with other External Data sources (CSV, JSON, LDAP) odbc_generic connector with the External Data extension

Installation

[edit]
  • Download and place the file(s) in a directory called ODBC in your extensions/ folder.
  • Add the following code at the bottom of your LocalSettings.php file:
    wfLoadExtension( 'ODBC' );
    
  • Ensure the PHP ODBC extension (ext-odbc) is installed and enabled:
    • Windows: Usually included; enable extension=php_odbc.dll in php.ini if needed.
    • Linux (Debian/Ubuntu): sudo apt install php-odbc
    • Linux (RHEL/CentOS): sudo yum install php-odbc
  • Install an ODBC driver for your target database (e.g., Microsoft ODBC Driver for SQL Server, MySQL Connector/ODBC, PostgreSQL ODBC).
  • Configure data sources in LocalSettings.php (see Configuration below).
  • Developers running tests should run composer install within the ODBC directory.
  • Yes Done – Navigate to Special:Version on your wiki to verify that the extension is successfully installed.

Configuration

[edit]

Data Sources ($wgODBCSources)

[edit]

Each data source gets a unique ID key in $wgODBCSources. Three connection modes are supported:

Mode 1 — System/User DSN

[edit]
$wgODBCSources['my-access-db'] = [
    'dsn'      => 'MyAccessDSN',
    'user'     => '',
    'password' => '',
];

Mode 2 — Driver-based connection

[edit]
$wgODBCSources['sql-server'] = [
    'driver'   => 'ODBC Driver 17 for SQL Server',
    'server'   => 'localhost,1433',
    'database' => 'MyDatabase',
    'user'     => 'sa',
    'password' => 'YourPassword123',
    'trust_certificate' => true,
];

Mode 3 — Raw connection string

[edit]
$wgODBCSources['oracle-db'] = [
    'connection_string' => 'Driver={Oracle in OraDB19Home1};DBQ=myserver:1521/myservice;',
    'user'     => 'myuser',
    'password' => 'mypass',
];

Prepared Statements (recommended)

[edit]
$wgODBCSources['employees'] = [
    'driver'   => 'ODBC Driver 17 for SQL Server',
    'server'   => 'hr-server.local,1433',
    'database' => 'HumanResources',
    'user'     => 'wiki_reader',
    'password' => 'ReadOnly123',
    'prepared' => [
        'get_employee' => 'SELECT FirstName, LastName, Department FROM Employees WHERE EmployeeID = ?',
        'dept_list'    => 'SELECT DISTINCT Department FROM Employees ORDER BY Department',
        'search'       => 'SELECT FirstName, LastName, Title FROM Employees WHERE Department = ? AND Title LIKE ?',
    ],
];

Per-Source Options

[edit]
Option Type Description
timeout integer Per-source query timeout in seconds (overrides $wgODBCQueryTimeout).
allow_queries boolean Allow composed (ad-hoc) queries for this source even when $wgODBCAllowArbitraryQueries is false. Use sparingly.
charset string Explicit encoding (e.g. 'ISO-8859-1'). When set, encoding auto-detection is skipped for this source.
dsn_params array Extra key=value pairs appended to the driver connection string (e.g. ['Encrypt' => 'yes']).
trust_certificate boolean Add TrustServerCertificate=yes for SQL Server with self-signed certificates.
host string Progress OpenEdge only. Alternative to server.
db string Progress OpenEdge only. Alternative to database.
prepared array Associative array of named prepared SQL statements: 'name' => 'SQL with ? placeholders'.

Global Parameters

[edit]
Variable Type Default Description
$wgODBCSources array {} Associative array of ODBC data source configurations. Each key is a source ID.
$wgODBCAllowArbitraryQueries boolean false If true, wiki editors with odbc-query permission can pass composed (ad-hoc) SQL. Keep false in production.
$wgODBCMaxRows integer 1000 Maximum number of rows returned by any single ODBC query.
$wgODBCQueryTimeout integer 30 Query timeout in seconds.
$wgODBCCacheExpiry integer 0 Number of seconds to cache query results. 0 disables caching. Cached per unique SQL+parameters+maxRows combination.
$wgODBCExternalDataIntegration boolean true Register as an odbc_generic connector for External Data. Must be set before wfLoadExtension( 'ODBC' ).
$wgODBCMaxQueriesPerPage integer 0 Maximum #odbc_query calls per page render. 0 = unlimited.
$wgODBCSlowQueryThreshold float 0 Execution time in seconds above which a query is logged to the odbc-slow log channel. 0 = disabled.
$wgODBCMaxConnections integer 10 Maximum cached connections per PHP worker process. In PHP-FPM, total system connections = this × active workers.

Permissions

[edit]
Right Description Default Groups
odbc-query Use ODBC parser functions (#odbc_query, etc.) on wiki pages sysop
odbc-admin Access Special:ODBCAdmin for connection testing, table browsing, and test queries sysop

Grant to additional groups as needed:

$wgGroupPermissions['user']['odbc-query'] = true;

Parser Functions

[edit]

The extension provides five parser functions that work as a pipeline: fetch data with #odbc_query, display with #odbc_value, #for_odbc_table, or #display_odbc_table, and optionally reset with #odbc_clear.

All parser function names are case-insensitive{{#odbc_query:}}, {{#ODBC_QUERY:}}, and {{#Odbc_Query:}} are all equivalent.

#odbc_query — Fetch Data

[edit]

Executes a query and stores results in page-scoped variables.

Prepared statement mode (recommended):

{{#odbc_query: source=employees
 | query=get_employee
 | parameters=12345
 | data=first=FirstName,last=LastName,dept=Department
}}

Composed query mode (requires allow_queries or $wgODBCAllowArbitraryQueries):

{{#odbc_query: source=my-source
 | from=Products
 | data=name=ProductName,price=UnitPrice
 | where=Active=1
 | order by=ProductName ASC
 | limit=50
}}

#odbc_value — Display a Single Value

[edit]
{{#odbc_value: name}}
{{#odbc_value: dept | (Unassigned) }}
{{#odbc_value: name | N/A | 2 }}
{{#odbc_value: name | N/A | last }}

#for_odbc_table — Loop with Inline Wikitext

[edit]
{| class="wikitable"
! Name !! Department
{{#for_odbc_table:
{{!}}-
{{!}} {{{name}}} {{!}}{{!}} {{{dept}}}
}}
|}

#display_odbc_table — Loop with Wiki Template

[edit]
{{#display_odbc_table: template=EmployeeRow }}

Calls {{EmployeeRow|name=...|dept=...|email=...}} for each row.

#odbc_clear — Clear Stored Data

[edit]
{{#odbc_clear:}}
{{#odbc_clear: name,dept}}

For complete syntax, parameters, and worked examples, see ODBC Guide.

External Data Integration

[edit]

When External Data is installed and $wgODBCExternalDataIntegration is true (the default), ODBC registers an odbc_generic connector. This allows External Data's parser functions to query ODBC sources:

$wgExternalDataSources['my-odbc'] = [
    'type'     => 'odbc_generic',
    'driver'   => 'MySQL ODBC 8.0 Unicode Driver',
    'server'   => 'mysql-server.local',
    'name'     => 'production_db',
    'user'     => 'readonly',
    'password' => 'secret',
];
{{#get_db_data: db=my-odbc
 | from=users
 | data=username=user_name,email=user_email
 | where=active=1
}}
To disable integration, set $wgODBCExternalDataIntegration = false; before wfLoadExtension( 'ODBC' ); in LocalSettings.php .

Admin Interface

[edit]

Special:ODBCAdmin (requires odbc-admin permission) provides:

  • Connection overview — View all configured sources with driver, server, and database details
  • Connection testing — Verify ODBC connectivity to each source
  • Table browser — List all tables available in a source
  • Column inspector — Inspect table schema and column types
  • Query runner — Execute SELECT queries and view results (non-SELECT blocked; SQL sanitization enforced)

Supported Databases

[edit]

Any database with an ODBC driver should work. Tested and known-compatible drivers:

Database Common ODBC Driver
Microsoft SQL Server ODBC Driver 17 for SQL Server / ODBC Driver 18 for SQL Server
MySQL / MariaDB MySQL ODBC 8.0 Unicode Driver
PostgreSQL PostgreSQL Unicode
Oracle Oracle in OraDB19Home1
Microsoft Access Microsoft Access Driver (*.mdb, *.accdb)
IBM DB2 IBM DB2 ODBC DRIVER
SQLite SQLite3 ODBC Driver
SAP HANA HDBODBC
Snowflake SnowflakeDSIIDriver
Amazon Redshift Amazon Redshift (x64)
Progress OpenEdge Progress OpenEdge (uses host/db keys)

Security

[edit]

Design Principles

[edit]
  • Read-only by design — Only SELECT queries are permitted. DROP, DELETE, INSERT, UPDATE, EXEC, and 40+ other dangerous patterns are blocked by a multi-layered sanitizer.
  • Prepared statements — The recommended query mode; prevents SQL injection by design.
  • Identifier validation — Table and column names are validated against a strict regex (alphanumeric, underscores, and up to 3 dot-separated segments only).
  • Error sanitization — Credentials are stripped from ODBC error messages before display.
  • CSRF protection — All state-changing actions in Special:ODBCAdmin require a valid session token.
  • Connection pooling limits — Configurable per-worker connection cap with LRU eviction prevents resource exhaustion.

Recommendations

[edit]
  1. Use prepared statements wherever possible
  2. Keep $wgODBCAllowArbitraryQueries = false in production
  3. Use a read-only database account (SELECT-only privileges)
  4. Restrict odbc-query to trusted user groups
  5. Secure LocalSettings.php file permissions (contains plain-text credentials)

Troubleshooting

[edit]
"ODBC extension not found"
Install ext-odbc: apt install php-odbc (Debian/Ubuntu) or enable extension=php_odbc.dll (Windows). Restart the web server.
"Could not connect"
Verify the ODBC driver is installed (odbcinst -q -d on Linux, ODBC Data Source Administrator on Windows). Test the DSN outside of MediaWiki with isql. Check firewall rules, credentials, and server hostname.
"Arbitrary SQL not allowed"
Either define prepared statements (recommended), set 'allow_queries' => true on the specific source, or set $wgODBCAllowArbitraryQueries = true globally.
"Invalid identifier" / "Illegal SQL pattern"
The query contains blocked characters or keywords. Use prepared statements, or ensure composed queries use only allowed patterns.
Query returns no results
Check column-name case sensitivity, verify data= mappings, review where= conditions, and use Special:ODBCAdmin to browse the table structure.
Performance issues
Enable caching ($wgODBCCacheExpiry), add database indexes, use limit=, and consider slow-query logging ($wgODBCSlowQueryThreshold).

Technical Details

[edit]
  • Architecture: Modular PHP classes — ODBCConnectionManager (connection pooling, DSN construction, LRU eviction), ODBCQueryRunner (query execution, SQL sanitization), ODBCParserFunctions (parser function implementations), EDConnectorOdbcGeneric (External Data bridge), SpecialODBCAdmin (admin interface).
  • Stability: 242 PHPUnit tests with PHPStan level 3 static analysis and MediaWiki code style enforcement via PHP_CodeSniffer.
  • CI: GitHub Actions pipeline with PHP syntax lint (7.4–8.4), PHPUnit, PHPStan, PHPCS, and release-readiness checks.

See also

[edit]