Everything behind the numbers on the pgrecon page: what ran, which versions, what each tool needed to run at all, and how to reproduce it. August 2026.
Every converter claims to convert an Oracle schema. The benchmark asks one narrower question: when the tool's output is applied to a real PostgreSQL, statement by statement, how many statements does PostgreSQL itself reject? An error here is not a missing feature or a style complaint - it is a statement the target database refuses. That is the same bar a real migration hits in production, whether a tool warned about it or not.
A zero on that bar does not mean everything converts, and the number only means something next to how much was attempted; the coverage numbers are stated below with the same precision as the error counts.
tests/fixtures/synthetic/synthetic_schema.sql.Source database: Oracle XE 21c (21.3), loaded with all nine
schemas. Target: a stock postgres:16 container. No
compatibility extensions installed unless a tool's own output
requires one, in which case that is recorded below.
| Tool | Version / mode |
|---|---|
| pgrecon | 0.5.0, pgrecon convert from an offline dump |
| CYBERTEC ora_migrator | current release, August 2026, over oracle_fdw 2.9.0 (Oracle Instant Client 23) |
| Ora2Pg | v25.0, TYPE=TABLE,VIEW,SEQUENCE,TRIGGER,FUNCTION,PROCEDURE,PACKAGE |
| EDB Migration Toolkit | 55.13.0, -offlineMigration, community PostgreSQL target |
| AWS Schema Conversion Tool | current build, August 2026, via its batch CLI (.scts scripts) |
Each tool's generated SQL was applied to a fresh database in the
same PostgreSQL 16 with psql -qX and
ON_ERROR_STOP off, so every statement gets its chance;
the error count is the number of lines PostgreSQL answered with
ERROR. Function bodies were applied with
check_function_bodies on wherever the tool's own output
did not override it. Where a tool emitted per-schema files they were
applied in the tool's own recommended order.
Runs were kept as fair as each tool allows; everything a tool needed beyond its documentation is recorded here.
ON_ERROR_STOP inside itself, so as shipped it
stops at its own first error (OE stopped at statement 29); the
self-abort was stripped to measure the full count. Its
SYS_GUID mapping silently requires the
uuid-ossp extension, which was pre-created.libaio symlink for the instant client on
Debian 13). Two schemas - utPLSQL and the private lab schema -
crashed whole in db_migrate_prepare on the
staging schema's own foreign keys and were never attempted;
they are counted as crashes, not errors. PL/SQL is out of its
scope by design and is not counted against it.aws_oracle_ext runtime extension - the
portability question a client actually faces. Its converted
routines create cleanly (PostgreSQL only syntax-checks
function bodies) and depend on that extension when called;
the count reflects statements rejected at apply time.| Converter | Statements rejected | Notes |
|---|---|---|
| pgrecon 0.5 | 0 | every decline a named residue line |
| CYBERTEC ora_migrator | 40 | plus two whole-schema crashes |
| Ora2Pg v25 | 77 | 49 on OE, 18 on the lab schema, 8 on RECON_TEST; clean on the simple estates |
| EDB MTK 55.13 | 135 | of 477 emitted statements; the low counts on package libraries are absence, not quality |
| AWS SCT | 481 | clean on HR only; 214 on utPLSQL, 76 on Alexandria, 73 on PLJSON |
Coverage, stated with the same precision: pgrecon converted 51 percent of all objects mechanically - above 90 percent on the business-shaped schemas, far below on the object-type and package showcases, which nothing converts mechanically. Every unconverted object is one line in the residue report with a reason. One hierarchical view was additionally verified row-for-row against the live Oracle running the original. pgrecon's numbers were re-verified at 0.5.0; the other tools' outputs were unchanged from their original runs.
podman run -d --name oracle-xe -e ORACLE_PASSWORD=... gvenzl/oracle-xe:21 podman run -d --name pg-target -e POSTGRES_PASSWORD=... postgres:16 # install HR/OE/CO from db-sample-schemas v21.1, the four projects # from their repositories, RECON_TEST from this repo's fixture pip install pgrecon==0.5.0 pgrecon script # extraction script; run per schema via sqlplus pgrecon load dump_dir --db est.db pgrecon convert --db est.db psql -qX -f schema_pg.sql 2>&1 | grep -c ^ERROR
Run each competing tool per its own documentation against the same schemas, apply with the same psql invocation, count the same way. If a number here looks wrong, that is a fair reaction - reproduce it and say so on the issue tracker.