Oracle → PostgreSQL · database compatibility

Paritas In development

An Oracle-compatible PostgreSQL, built around one honest promise: we can tell you exactly where compatibility ends (for your code, with measured evidence) and close the gaps that matter to you.

Paritas is PostgreSQL 18 with an Oracle mode that compiles and runs real PL/SQL: packages, triggers, collections and exceptions. It is working toward 1.0 against eight published acceptance criteria, and every figure on this page comes from a dated run against Oracle Database 21c.

Paritas is not for sale yet: 1.0 has not shipped, and it ships only when all eight criteria hold. The test harness behind it already runs, and we are happy to show it live.

Paritas oracle-compatible · postgres
Base PostgreSQL 18 Reference Oracle 21c Method Measured Status Working to 1.0
The problem nobody sells against

The dangerous half of a migration is invisible

When a company moves off Oracle, everyone focuses on converting the code, the visible half. The invisible half is that PostgreSQL is not Oracle: in places it computes a different answer to the same expression. Not an error. A different number.

The worst class of migration bug. A pricing or tax expression converts cleanly, passes code review, and deploys fine, then returns a subtly wrong number in production, found by a customer. No error at build time. No error in test. You can't find these gaps by reading documentation; you can only find them by running the same SQL against both databases and comparing every answer.
Measured, not assumed

Same code, different answers

Three real results, each measured on live engines. Every one converts cleanly, and none raises an error you would see at build time.

Oracle Database 21c is the source of truth. Measured August to October 2026.
CodeOraclePostgreSQLParitas
SELECT 3.4e38f * 10f
binary floats multiplied past the top of the type
infan error: the literal is refused, and the nearest equivalent raises value out of rangeinf ✓
SELECT 1 UNION SELECT 2 INTERSECT SELECT 2
set operators without parentheses
21, 2: INTERSECT binds tighter, so other rows come back2 ✓
FOR i IN REVERSE 1 .. 3 LOOP
a loop that walks backwards
runs 3, 2, 1runs no iteration at all: its REVERSE takes the bounds the other way roundruns 3, 2, 1 ✓

A loop that walks a collection backwards silently does nothing; a report built on a set query silently gains rows. Paritas gives Oracle's answer in each case because we measured the difference rather than guessing at it. The first fix has since been taken into the upstream open-source project.

The approach

We built the test harness before the database

The moat is not the database. Anyone can fork one. It's a differential test harness: Oracle Database 21c, stock PostgreSQL and the unmodified open-source base Paritas is built on, all running beside Paritas. The same code goes to each engine and every answer is compared against Oracle's. A difference is only real once it is measured on a live engine, never assumed from a manual: on 9 October 2026 two fixes written from Oracle's own manual gave the wrong answer on a real Oracle 21c.

The differential corpus

762 cases of SQL and PL/SQL, each with the answer a real Oracle instance returned. Every engine runs every case, and every verdict is kept from run to run, so a change that fixes one answer and breaks another shows up in the next run.

The application gauntlet

591 units and 92,000 lines of real PL/SQL from nine schemas, among them the Alexandria, Logger, utPLSQL and PL/JSON libraries and Oracle's HR and OE samples, compiled unchanged. It ranks what breaks, so the most common blocker is fixed first.

Stress and sanitizer

170 stress cases, an AddressSanitizer build in continuous integration, and a 24-hour soak with flat memory on the release candidate. A database that gives Oracle's answers and then falls over is not compatible.

Where 1.0 stands

Eight criteria, each one a measurement

The bar for 1.0 was set in advance, as numbers rather than adjectives. Here is where each stood on 12 October 2026 (the call-site count is from 8 October).

Criterion1.0 needsNow
Real Oracle PL/SQL compiles unchanged90% of the gauntlet's 253 package-level units that Oracle itself compiles141 (56%)
Answers match Oracle95% of the 762 corpus cases593 (78%); the unmodified base gives 514 (67%)
It survivesno crash, sanitizer clean, a 24-hour soak with flat memoryno crash in 170 stress cases and sanitizer clean; five known crash cases still open, and the soak runs last
The built-in packages applications call exist70% of 2,994 call sites1,436 (48%)
Errors behave like Oracle (the codes handlers catch, SQLCODE, SQLERRM, RAISE_APPLICATION_ERROR)all 38 cases31
Limitations listed honestlya published listwritten, and kept current
Maintainable from the documents aloneCI, the gate and the runbooks, each procedure rehearsed once from its runbookCI and the gate run; three scripts, two runbooks and the rehearsals to go
A release existsa 1.0.0-rc1 tag and changelog, reproducible from a clean clonenot yet

The gauntlet holds 316 package-level units; 63 of them do not compile on Oracle 21c either, and code Oracle refuses measures nothing. About 760 of the 2,994 call sites are in packages left out of 1.0 by decision (below), so the most that criterion can reach in 1.0 is about 75%.

What works today

The Oracle that real code is written in

Each item below is tested against Oracle 21c's measured answers, and most arrived in the last few weeks because the gauntlet ranked them first.

Packages

  • Specification and body, with state kept per session
  • Package records, constants, cursors and initialization sections
  • Types, subtypes and exceptions declared in a package and used from other code
  • Private body items, and recursion that keeps each caller's values

The PL/SQL language

  • SUBTYPE, and 13 predefined subtypes such as POSITIVE and NATURAL
  • PLS_INTEGER, SIMPLE_INTEGER, SYS_REFCURSOR and cursor attributes
  • SELECT INTO, EXECUTE IMMEDIATE, and procedure calls without CALL
  • FOR ... IN REVERSE in Oracle's order

Exceptions

  • User-defined and predefined exceptions, raised and caught by name
  • PRAGMA EXCEPTION_INIT with Oracle's scope and codes
  • RAISE_APPLICATION_ERROR, and SQLCODE and SQLERRM in handlers

Collections and types

  • Nested tables, VARRAY and INDEX BY PLS_INTEGER collections, with EXTEND
  • BULK COLLECT, TABLE() in a query, and pipelined functions
  • Schema-level object types (attributes) and collection types, with constructors

Triggers and SQL

  • Oracle's trigger syntax: the body in the statement, :new and :old, INSERTING, UPDATING, DELETING, REFERENCING
  • MINUS, Oracle's set-operator order, and ROWNUM in single-table queries
  • IEEE arithmetic for BINARY_FLOAT and BINARY_DOUBLE
  • DBMS_OUTPUT, DBMS_LOB, UTL_RAW and part of DBMS_UTILITY

Running it

  • One server, two dialects: Oracle mode on its own port beside PostgreSQL's, so no session has to switch
  • Backup and restore of Oracle-mode databases with pg_dump
  • Builds on Linux and on Windows, where three Oracle-mode tests still fail
Where compatibility ends

Knowing the limits is the product

Any architect will test a compatibility claim within an hour. Say "Oracle compatible" without limits and you lose the account the moment they find the first gap. So we write down where it ends: our list of limitations runs to more than 140 entries, each saying what happens, and most what to do instead. The headlines are below.

Left out of 1.0, by decision

  • Object types with methods: type bodies, member functions, UNDER, REF
  • Autonomous transactions: refused when the code compiles, because a fake would be a trap
  • The network packages (UTL_HTTP, UTL_TCP, UTL_SMTP, UTL_MAIL)
  • The XML packages (DBMS_XMLGEN, DBMS_XMLDOM, DBMS_XMLPARSER)
  • DBMS_SCHEDULER and DBMS_JOB
  • Optimizer hints, which are read as comments

Open today

  • Integer division truncates: SELECT 10/4 is 2, where Oracle, which has no integer type, gives 2.5
  • A number turned into text keeps its leading zero: TO_CHAR(0.5) is 0.5, where Oracle gives .5
  • INDEX BY VARCHAR2 collections and FORALL
  • ROWNUM in joins and in the nested pagination idiom; FETCH FIRST works
  • The (+) outer join, which pgrecon rewrites to LEFT JOIN
  • DBMS_SQL, UTL_FILE and four more packages, planned for 1.0
The claim we can actually defend. Not "we're Oracle compatible." Instead: we tell you exactly where compatibility ends, for your code, with measured evidence, and we close the gaps that matter to you. That turns compatibility from a marketing adjective into a per-customer, measured fact.
Assessment and destination, one pipeline

It plugs straight into pgrecon

pgrecon tells you what your Oracle estate contains and what a migration will cost. The Paritas harness tells you which of that estate behaves differently on the destination (measured, per expression). The two already share their plumbing: the tables the gauntlet compiles real PL/SQL against are extracted and converted by pgrecon itself. Know the scope, then know the risk, before you commit.

Being precise about status

What exists today

We would rather you hear the limits now than in six months.

Built and working

  • The harness: the corpus, the gauntlet and the stress suite, with a dated run behind every figure here
  • Paritas builds, installs and runs as PostgreSQL 18 with an Oracle mode, fully rebranded
  • Every change passes a gate (a build with zero warnings and the full regression suites) and independent review
  • Every expected answer in its tests is Oracle 21c's, measured, never copied from a manual

Upstream, done right

Paritas builds on Apache-2.0-licensed open-source technology, so it is fully legal, with proper attribution files. Where we find a defect that belongs upstream, we send it back with a reproduction the maintainers can run, building credibility in the PostgreSQL world rather than maintaining a private fork of everything.

It is working: the floating-point fix above was merged into the upstream open-source project on 3 September 2026. Since then we have filed eleven more issue reports with reproductions and opened ten pull requests with fixes, all still under review on 13 October 2026. Paritas carries its own fix for each of those pull requests meanwhile, and drops it when upstream's version arrives.

Still to come before 1.0

  • 87 more real units compiling, and 131 more corpus answers matching Oracle
  • The five known crash cases, then the 24-hour soak
  • DBMS_SQL, UTL_FILE, DBMS_ASSERT, DBMS_RANDOM, DBMS_APPLICATION_INFO and DBMS_CRYPTO
  • The release runbooks, and a 1.0.0-rc1 tag

Paritas cannot be bought today, and we give no date: 1.0 ships when the eight criteria hold, not before.

Early, and honest about it

Moving off Oracle? Let's measure the risk

We can show you the harness running (it's more convincing to watch than to describe) and tell you exactly where compatibility ends for your code.