AI Proof Pricing Book a demo Scan your code free

Hard sources — not covered by free tools

Also parsed — certify what free tools miss

Targets

Warehouses

Runtimes

After migration

Free tools cover the SQL. We cover SAS, COBOL, Alteryx, Qlik, ODI, DataStage — and the proof. Start a pilot →

Convert Oracle PL/SQL to modern cloud SQL

Parser-driven modernization of packages, procedures, functions, triggers, and views — including cursor loops, CONNECT BY hierarchies, and BULK COLLECT processing. Full lineage, automated conversion, validated parity.

MigryX analyzer showing parsed Oracle PL/SQL packages as an interactive lineage graph PL/SQL package parsed into interactive lineage graph
Architecture

Oracle PL/SQL in. Native platform out.

One source, every target. Deterministic parsers read the estate and emit native code for the platform you pick — not PL/SQL wrapped in a compatibility layer.

Oracle PL/SQL estate → MigryX parser → native platforms

Oracle PL/SQL
PackagesProcs + funcs
Cursor loopsRow-by-row
CONNECT BYHierarchies
BULK COLLECT%ROWTYPE
MigryX Parser
Deterministic parseAI where it helps
Lineage / STTMBefore cutover
PL/SQL ASTDeterministic
Set-based emitNo row loops

The parser is deterministic: the same input produces the same output on every run. Every output is validated against the original, row by row, before go-live.

Why now

Procedural code on a platform priced per core

Row-by-row processing fights the target architecture

Cursor loops with per-row DML are normal in PL/SQL and pathological on a columnar warehouse. Lifting them unchanged produces a migration that runs slower than the system it replaced, which is how cloud programmes lose their business case.

Licensing is tied to cores you must keep provisioned

Capacity is sized for peak batch windows and paid for continuously, per core, with options scoped separately. Warehouses that separate storage from compute let the batch window scale up and then stop costing money.

Business rules only exist inside packages

Decades of logic sit in package bodies, triggers and views. There is no design document, so the code is the specification, and reading it well enough to reimplement it is the actual project.

See it in action

CONNECT BY hierarchies — syntax with no equivalent

Oracle's hierarchical query syntax, with LEVEL, SYS_CONNECT_BY_PATH and ORDER SIBLINGS BY, has no counterpart in modern SQL dialects. It has to be re-expressed as recursion, and that rewrite is mechanical but easy to get subtly wrong.

Oracle PL/SQL
-- Organisational rollup with CONNECT BY
SELECT  employee_id,
        manager_id,
        LEVEL                                   AS depth,
        SYS_CONNECT_BY_PATH(employee_name, '/') AS org_path,
        CONNECT_BY_ROOT employee_name           AS top_manager,
        CONNECT_BY_ISLEAF                       AS is_leaf
FROM    employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id
ORDER SIBLINGS BY employee_name;
MigryX
converts
Snowflake SQL
-- CONNECT BY → recursive CTE
WITH RECURSIVE org AS (
    -- START WITH
    SELECT  employee_id, manager_id, employee_name,
            1                              AS depth,
            '/' || employee_name           AS org_path,
            employee_name                  AS top_manager
    FROM    employees
    WHERE   manager_id IS NULL

    UNION ALL

    -- CONNECT BY PRIOR employee_id = manager_id
    SELECT  e.employee_id, e.manager_id, e.employee_name,
            o.depth + 1,
            o.org_path || '/' || e.employee_name,
            o.top_manager
    FROM    employees e
    JOIN    org o ON e.manager_id = o.employee_id
)
SELECT  o.*,
        -- CONNECT_BY_ISLEAF
        CASE WHEN NOT EXISTS (
                 SELECT 1 FROM employees c
                 WHERE c.manager_id = o.employee_id)
             THEN 1 ELSE 0 END AS is_leaf
FROM    org o
ORDER BY org_path;

START WITH becomes the anchor member and CONNECT BY PRIOR becomes the recursive join. LEVEL becomes an incremented depth, the path is accumulated explicitly, and leaf detection becomes a NOT EXISTS test.

Coverage

What gets converted

Every PL/SQL construct in your packages maps to a defined target equivalent, recorded in the lineage report.

Oracle PL/SQL Construct Target Equivalent Notes
Package specification and bodyModule of related routinesPublic and private routines separated
Stored procedureStored procedure or scripted taskParameter modes IN, OUT and IN OUT
FunctionScalar or table functionDeterministic functions inlined where valid
Cursor FOR loopSet-based statementPer-row DML rewritten as one operation
BULK COLLECT / FORALLSet-based insert or MERGEBatching becomes a single statement
CONNECT BY hierarchyRECURSIVE CTELEVEL, ROOT, ISLEAF and PATH rewritten
Analytic functionsWindow functionsPartitioning and framing preserved
MERGE statementMERGEMatched and not-matched clauses carried over
Global temporary tableTemporary or transient tableSession scope mapped to target semantics
Collections and recordsStructured types or DataFramesNested tables and VARRAYs flattened
Exception blocksExplicit error handlingNamed exceptions and SQLCODE preserved
TriggerPipeline step or stream taskRow-level triggers made explicit in the load
SequenceSequence or identity columnCurrent value and increment carried over
DBMS_OUTPUT / UTL_FILELogging and file writesServer file access flagged for review
Dynamic SQL (EXECUTE IMMEDIATE)Parameterized SQLConstructed statements reported for review
Validation

Every conversion is validated to row-level parity

MigryX Data Matching compares Oracle output against the new warehouse output, row by row and column by column, with configurable tolerance rules and mismatch drill-down.

See how Data Matching works →
FAQ

Oracle PL/SQL modernization questions

What do you need, a database connection or source files?

Source files are enough. DDL and package source extracted from the data dictionary or from version control is the normal input, so parsing does not require production database access. A connection is only useful later, during parity validation.

What happens to cursor loops that do row-by-row DML?

They are rewritten as set-based statements wherever the loop body permits it, because carrying the row-at-a-time pattern to a columnar warehouse is the most common reason migrated batch runs are slower than the Oracle original.

Can procedural logic survive if the target has no PL/SQL?

Yes, in one of two forms. Logic that is really set manipulation becomes SQL, and logic that is genuinely procedural becomes a stored procedure in the target's own scripting language or a Python task, depending on which target you are moving to.

How is dynamic SQL treated?

EXECUTE IMMEDIATE and DBMS_SQL statements are extracted and reported rather than converted blind, because the statement text is assembled at runtime and a parser cannot prove what it will contain.

What to bring to a Oracle PL/SQL assessment

Review a representative sample with us →