Hard sources — not covered by free tools
Also parsed — certify what free tools miss
Runtimes
After migration
Stored procedures, packages, functions, and triggers parsed structurally. Converted to PySpark notebooks and Spark SQL on Databricks with Delta Lake. 2,000+ built-in function mappings, full lineage, validated parity.
Deterministic parsers read the estate and emit native Databricks code — not PL/SQL wrapped in a compatibility layer.
Oracle PL/SQL → MigryX parser → PySpark + Delta + Workflows
Deterministic parseAI where it helpsMigryX AI handles the logic parsers cannot resolve alone, and every change it makes goes through the same parity checks. It runs on a model you approve, air-gapped if your estate requires it.
Oracle packages bundle specification and body into monolithic database objects. MigryX decomposes them into clean Python modules with clear class structure, public APIs preserved. 350 packages decomposed across a single engagement.
Oracle's proprietary START WITH...CONNECT BY PRIOR syntax has no direct Spark equivalent. MigryX converts hierarchical queries to recursive CTEs in Spark SQL or equivalent PySpark GraphFrames logic, preserving LEVEL, SYS_CONNECT_BY_PATH, and CONNECT_BY_ROOT.
Oracle's BULK COLLECT / FORALL pattern fetches rows into PL/SQL collections for batch DML. On Databricks, this maps naturally to DataFrame batch operations that distribute across the cluster. Row-by-row cursor loops become set-based transformations.
A PL/SQL procedure using explicit cursors and BULK COLLECT for batch processing -- converted to native PySpark DataFrame operations on Databricks. No row-by-row processing, no single-node bottleneck.
-- Procedure: process_customer_segments
CREATE OR REPLACE PROCEDURE process_segments AS
TYPE t_cust IS TABLE OF customers%ROWTYPE;
l_custs t_cust;
CURSOR c_active IS
SELECT * FROM customers
WHERE status = 'ACTIVE'
AND total_spend > 1000;
BEGIN
OPEN c_active;
LOOP
FETCH c_active BULK COLLECT
INTO l_custs LIMIT 5000;
EXIT WHEN l_custs.COUNT = 0;
FORALL i IN 1..l_custs.COUNT
INSERT INTO customer_segments VALUES (
l_custs(i).cust_id,
DECODE(l_custs(i).total_spend,
NULL, 'Unknown',
'Platinum'),
NVL(l_custs(i).region, 'Unassigned'),
SYSDATE
);
COMMIT;
END LOOP;
CLOSE c_active;
END;
# PL/SQL procedure → PySpark on Databricks
from pyspark.sql import functions as F
def process_segments():
df = spark.read.table("customers")
segmented = (
df.filter(
(F.col("status") == "ACTIVE") &
(F.col("total_spend") > 1000)
)
.withColumn("segment",
F.when(F.col("total_spend").isNull(),
"Unknown")
.otherwise("Platinum"))
.withColumn("region",
F.coalesce(F.col("region"),
F.lit("Unassigned")))
.withColumn("processed_date",
F.current_date())
.select("cust_id", "segment",
"region", "processed_date")
)
segmented.write.format("delta") \
.mode("append") \
.saveAsTable("customer_segments")
process_segments()
Cursor loop with BULK COLLECT replaced by distributed DataFrame operations. DECODE mapped to F.when().otherwise(). NVL mapped to F.coalesce(). SYSDATE mapped to F.current_date(). Output writes to Delta Lake with ACID guarantees.
| Oracle PL/SQL Component | Databricks Equivalent | Notes |
|---|---|---|
| Stored Procedure | Python function | Parameters, exception handling preserved |
| Package (spec + body) | Python module | Public API as module exports, private as internal |
| CONNECT BY hierarchical query | Recursive CTE (Spark SQL) | LEVEL, SYS_CONNECT_BY_PATH preserved |
| BULK COLLECT / FORALL | DataFrame batch operations | Set-based processing replaces row batching |
| Trigger (BEFORE/AFTER) | Delta Live Tables expectations | Row-level and statement-level logic mapped |
| DECODE | F.when().otherwise() | Multi-branch DECODE fully expanded |
| NVL / NVL2 | F.coalesce() | NVL2 three-arg pattern preserved |
| Sequence | monotonically_increasing_id() | Or Delta identity columns |
| Materialized View | Delta table | Refresh logic mapped to scheduled notebook |
| DBMS_SCHEDULER jobs | Databricks Workflow | Cron triggers, dependency chains preserved |
| EXECUTE IMMEDIATE | spark.sql() | Dynamic SQL string execution mapped |
| Cursor FOR loop | DataFrame iteration | Row-by-row logic converted to set-based ops |
Data Matching compares Oracle output against Databricks output -- row by row, column by column.
See how Data Matching works →28 regulated enterprises, including six global systemically important banks, have modernized with MigryX. Customer names are shared under NDA in a demo, with reference calls on request.
See all engagements →