Cross-engine conversion has a working order: deterministic transpiler first, generative AI only for what rules cannot convert, parity tests over everything. Run Ora2Pg or DMS Schema Conversion, let AI refine the residue — and treat every vendor "converts 90% automatically" figure as a claim to test on your code.
Tier: Advanced · Workflow area: Migration & Modernization · ~45 minutes
The temptation is to paste PL/SQL into a chat window and ask for PostgreSQL. Resist it. Transpilers are deterministic, auditable and honest about what they cannot do; LLMs are fluent, tireless and confidently wrong about semantics — NULL behavior, implicit commits, date arithmetic. The professional pipeline uses each where it is strong: rules for the bulk, generation for the residue, and parity tests (pb-15) as the only judge either one answers to.
Run the transpiler and capture its honesty. Ora2Pg assesses before it converts — start there:
# Assessment: complexity scoring and human-days estimate per object
ora2pg -t SHOW_REPORT --estimate_cost -c ora2pg.conf
# Convert the procedure estate
ora2pg -t PROCEDURE -o procedures.sql -c ora2pg.conf
ora2pg -t FUNCTION -o functions.sql -c ora2pg.conf
The output contains converted code and failure markers — grep them out into your residue list:
grep -n "ORA2PG_COMMENT\|FIXME\|autonomous_transaction" procedures.sql
Record the real automatic-conversion rate: objects converted clean / total. This number — measured on your code — is your answer to the vendor slide.
Triage the residue into buckets. Typical residue: autonomous transactions, CONNECT BY hierarchies the transpiler punted on, UTL_/DBMS_ package calls, bulk-collect patterns, dynamic SQL built from strings. Bucket each: mechanical (AI-refinable), architectural (needs a design decision — autonomous transactions have no direct Postgres equivalent; choose dblink, a queue table, or app-level restructuring), and retire (dead code pb-14 identified).
Refine mechanical residue with AI — one object, full context, explicit traps.
Convert this PL/SQL block to PL/pgSQL for PostgreSQL 16. It is the
residue Ora2Pg could not convert (its partial output and FIXME
markers included below, plus the already-converted target schema).
Semantic traps — handle each EXPLICITLY with a comment where your
conversion differs from Oracle behavior:
1. Oracle '' IS NULL; Postgres '' is a value. Flag every string
comparison this affects.
2. Oracle DATE arithmetic returns days as numbers; Postgres
returns intervals. Convert the date math accordingly.
3. Oracle implicit commits (DDL, autonomous txns); Postgres runs
in-transaction. State the transactional difference.
4. SYSDATE vs now()/clock_timestamp() — choose per statement and
justify (statement-stable vs real-time).
5. Exception codes: map Oracle SQLCODEs to Postgres SQLSTATEs;
do NOT swallow OTHERS silently.
Output: converted code + a DIFFERENCES table (line, Oracle behavior,
Postgres behavior, risk).
The DIFFERENCES table is the review surface. An AI conversion without one is unreviewable fluency.
Review the differences table, then compile. Load into a scratch database and let the engine catch what review missed:
psql -d migr_target -v ON_ERROR_STOP=1 -f procedures_refined.sql
Compilation success means syntax, nothing more. Semantics are next.
Prove behavior with parity tests — the non-negotiable gate. For each converted procedure, execute source and target against identical seeded inputs and diff the outcomes: result sets, output parameters, side-effect table states, and error behavior for invalid inputs. Build the harness per pb-15; even the quick version catches the classics:
-- Target side: same seeded inputs the Oracle side ran
CALL calc_customer_discount(1001, '2026-07-31'::date);
SELECT * FROM discount_audit WHERE customer_id = 1001;
-- diff against the Oracle-side capture, column by column,
-- with explicit NULL-vs-empty-string comparison
Expect the parity suite to catch AI conversions that compiled cleanly and run wrong — empty-string equality checks and date-boundary arithmetic are the usual culprits. Log every catch: procedure, defect, which pipeline stage produced it.
Assemble the conversion record. Per procedure: transpiler verdict, residue bucket, AI differences table, review sign-off, parity result. Estate-wide: the measured auto-conversion rate, the AI-failure log, and the retire list. This record is what makes the migration auditable — and what makes your next conversion estimate accurate.
@@ROWCOUNT/GET DIAGNOSTICS, TOP/LIMIT, transaction-scoped temp tables vs Postgres temp tables, MERGE behavior differences, and T-SQL's error-handling model (TRY/CATCH vs exception blocks).Converted procedures touch the same production data the originals did — a silently wrong conversion corrupts quietly and permanently. No converted object reaches production without its parity result attached, and the cutover keeps the source system queryable for reconciliation until the retention window closes.
Transpiler for the bulk, AI for the residue, parity tests as the judge — and every conversion percentage anyone quotes you, including your own tooling's, is a hypothesis until your parity suite has scored it.