SQLing Engine
Run PL/SQL on SQLite, DuckDB, Postgres, or MariaDB.
SQLing Engine is a PL/SQL interpreter that does not need
Oracle underneath it. Procedures, packages, cursors, exception handlers,
collections, SQL/XML, SQL/JSON, row triggers, and the (+)
outer-join notation all accepted — because the interpreter implements
PL/SQL itself and translates the embedded SQL to whichever backend you
hand it.
Where this helps
-
CI without an Oracle box
PL/SQL regression tests that need an Oracle instance block every feature branch waiting for a slot. SQLing Engine runs them in-process on a developer laptop or a CI worker — same packages, same cursors, same trigger lifecycle, no licensing drama.
-
Migration pipelines
You are translating a legacy schema to Postgres and need to verify that the stored functions still behave. The
--rewrite postgresflag emits the exact SQL text your target would see; the embedded interpreter runs the surrounding PL/SQL against SQLite in a test harness. -
MariaDB, in its Oracle mode
On MariaDB, SQLing Engine runs the server in its Oracle compatibility mode and translates what that mode still lacks. Stored functions, package functions and row-level triggers become native MariaDB objects, so reports and other clients that connect directly call them too. An application spread over several schemas keeps each one in a database of its own.
-
Embeddable PL/SQL
Oracle Reports and Oracle Forms are built on PL/SQL. If you are writing a reader for either (or anything else that needs PL/SQL semantics in a non-Oracle context), SQLing Engine is the piece you plug in instead of writing one.
What it accepts
-
The PL/SQL language
Anonymous blocks, packages and bodies, standalone procedures and functions, cursors (explicit and implicit),
FOR ... INloops, collections (VARRAY, nested table, index-by table), exception handlers (named andSQLCODE-based), records and%ROWTYPE. -
Oracle's SQL surface
SQL/XML (
XMLELEMENT,XMLAGG,XMLATTRIBUTES,EXTRACTVALUE), SQL/JSON (JSON_OBJECT,JSON_ARRAYAGG,JSON_TABLE,JSON_VALUE, …),MERGE,CONNECT BY,(+)outer joins, hierarchical cursors. -
Oracle's command surface
CREATE OR REPLACEfor procedures, functions, packages, views, triggers, sequences, directories;GRANT/REVOKEfor the DBA_* dictionary; row-level triggers with:NEW/:OLDonINSERT,UPDATEandDELETE;SET SERVEROUTPUT,SET SQLFORMAT,SET DEFINE,SPOOL.
Try it right now
PL/SQL Playground loads SQLing Engine into your
browser and runs PL/SQL against SQLite or Postgres (pgLite) —
in your own tab, nothing uploaded. The
Translate button there is the same rewrite surface the CLI
exposes as --rewrite BACKEND: PL/SQL in, target-dialect
SQL out. Several examples (quick start, the language tour, SQL
cursors and transactions, SET SQLFORMAT, HTP web pages, SQL/XML and
SQL/JSON) are preloaded.
Point it at your own database
Database Workbench looks like a SQLite browser —
object tree on the left, a worksheet in the middle, a results grid
at the bottom — and the worksheet is SQLing Engine. Open
a .db file in your tab and run packages, cursors,
FOR UPDATE loops, (+) outer joins,
MERGE, SQL/XML and SQL/JSON against the real rows
inside it. The data stays local the whole time — your
.db never leaves the browser.
The Translate button shows what each statement would
look like against Postgres or DuckDB — the same dry-run rewrite
the CLI exposes as --rewrite BACKEND, so you can
preview the migration output next to the SQL you already have.
The CLI
For scripts and pipelines, SQLing Engine ships as a signed Python
wheel we provide under a licence agreement. Installing it drops a
SQLing command onto your PATH; from there
the usage is standard.
# Run a script against an in-memory SQLite:
$ sqling script.sql
# Persist to a file, pick the DuckDB backend:
$ sqling -d app.db --engine duckdb script.sql
# Run against MariaDB, in its Oracle compatibility mode:
$ sqling --engine mariadb -d mariadb://app_user@db-host/app script.sql
# Translate PL/SQL to the backend you plan to migrate to:
$ sqling --rewrite postgres -c "SELECT NVL(x,0), DECODE(c,1,'one','other') FROM t"
SELECT COALESCE(x, 0), CASE WHEN (c) IS NOT DISTINCT FROM (1) THEN ('one') ELSE ('other') END FROM t;
Embed it
For a product that needs PL/SQL semantics in-process:
from sqling_engine import Interpreter # exact module name
# documented with the licence
db = Interpreter(database="app.db", capture_output=True)
db.run_source(open("procs.sql").read())
total = db.call("order_total", 1234)
for line in db.take_output():
log.info(line)
Point it at an existing driver connection with
Interpreter(connection=my_conn) and PL/SQL shares the
transaction with the host app.
Running PL/SQL where Oracle isn't an option?
Pilot licences, custom builds, and embedding support available for product teams and migration vendors. Contact us.