NEWS

MariaDB 13 Reaches GA With Native Compatibility for Oracle's PL/SQL

The new stable release of MariaDB Community Server adds REF CURSOR and RECORD support in stored routines, RETURNING for UPDATE, and more control over optimizer hints, targeting teams migrating from legacy databases.

MariaDB 13 Reaches GA With Native Compatibility for Oracle's PL/SQL
Image: Redação iMasters

O MariaDB Community Server 13.0 reached General Availability (GA) in September, according to a report by InfoQ, and the package of new features targets directly those working with hybrid databases or migrations coming from Oracle. The release brings native support for REF CURSOR and RECORD in stored routines, a more complete RETURNING clause, and improvements to the optimizer hints framework introduced in version 12.

It's worth noting the context: MariaDB follows a rolling release model, delivering new features quickly rather than aiming for long-term stability. Those who need LTS should wait for the next version planned for that purpose, 13.3, which will inherit these changes once they've matured.

REF CURSOR and RECORD: Less Rewriting When Leaving Oracle

The most common pain point for those porting Oracle PL/SQL applications to MySQL/MariaDB has always been the semantics of cursors and structured types. MariaDB 13 tackles this head-on with support for weak and strong REF CURSOR, which can be opened, iterated (fetched), and closed as local variables, package routine parameters, or package function return types.

In practice, an Oracle function that returns a reference cursor for the calling code to process row by row now has a direct portability path, without having to rewrite the logic as a set of isolated SELECTs. The RECORD type, which already existed for local variables, now also works as a stored routine parameter or stored function return type, and can be combined with REF CURSOR to work with structured row data, typical of those handling records coming from PL/SQL.

The important caveat: neither REF CURSOR nor RECORD yet work as parameters or return types for global routines (outside a package). This means teams migrating Oracle code need to organize their logic into MariaDB packages to take full advantage of the feature, something that was already expected given that MariaDB's package support was created precisely to mirror PL/SQL's package model.

RETURNING Comes to UPDATE, Saving a Trip to the Database

Until now, the RETURNING clause in MariaDB only applied to INSERT and DELETE. In version 13 it also works with UPDATE, and the practical gain is direct: you can capture the modified rows in the same statement that makes the change, without needing a subsequent SELECT.

The detail that sets this apart from a generic RETURNING is the combination with the OLD_VALUE() function. With it, you can retrieve both the old and new values of a column in a single trip to the database, the kind of operation that normally required two round trips (one SELECT before the UPDATE, another to check the result) or auxiliary triggers just for auditing. For those building audit trails, cache synchronization, or state-change logs directly in the application, this reduces latency and simplifies code that today depends on triggers.

The limitation for now: RETURNING in UPDATE only applies to single-table statements, so multi-table joins with cascading updates remain outside the feature's scope.

Optimizer Hints Become Easier to Target

MariaDB 12 had already introduced a hints framework for the query optimizer. Version 13 improves its ergonomics: Views, CTEs, and derived tables now automatically receive a query block name, which allows hints to target them without having to declare QB_NAME() manually.

For complex queries with multiple levels of subqueries and nested CTEs, this reduces boilerplate. When a block can't be identified by name alone (because it's deeply nested), the so-called QB_NAME locators serve as an explicit path to the right block. This is the kind of adjustment that matters to those who already handle execution plans manually and use hints as a fine-tuning tool in production, not as an academic curiosity.

Observability: Less SHOW CREATE TABLE, More Queryable Metadata

The observability and administration side also gained weight. The init_rpl_role variable, which previously only existed as a command-line option at startup, is now exposed as a system variable, allowing the server's replication role to be checked directly via SHOW VARIABLES or @@init_rpl_role, without having to inspect the boot process or configuration files.

Another change targets those who automate schema inspection: the I_S.STATISTICS and I_S.COLUMNS tables now include a CREATE_OPTIONS column, exposing storage-engine-specific options for indexes and columns that previously only appeared in the free-form text of SHOW CREATE TABLE. This matters for data lineage tools, schema audit scripts, and CI pipelines that validate table structure: parsing a structured column is more reliable than running regex against SHOW CREATE TABLE output.

Finally, I_S.SYSTEM_VARIABLES gained columns indicating whether a system variable is deprecated, making automated checks before upgrades easier, a recurring problem for teams that maintain multiple MariaDB instances across different versions.

What Still Needs a Closer Look

The InfoQ report doesn't detail the minimum MariaDB Connector version required to make use of RETURNING with OLD_VALUE(), nor updated client libraries for consuming REF CURSOR in packages, so anyone testing a PL/SQL migration should check MariaDB's official documentation before assuming full compatibility with drivers already in use. It also remains open to what extent support for REF CURSOR and RECORD in global routines will arrive in future versions, something that could further ease the portability of legacy code that doesn't use packages.

For those who currently maintain a homegrown compatibility layer between PL/SQL and MySQL/MariaDB, built the hard way with hand-rewritten stored procedures, MariaDB 13 reduces part of that friction, but doesn't eliminate the need to review each migrated routine case by case.

Translated from the Brazilian Portuguese original · Read the original