How a FastAPI-to-SQL*Plus gateway solved what modern drivers couldn't — preserving Arabic legacy encoding while making a 20-year-old database fully programmable.
An Oracle 10g database still powered real workflows, held financial transactions, employee records, and student data. The database wasn't the problem — getting modern apps to talk to it reliably was.
Legacy systems are rarely abandoned because they fail. They endure because they matter — embedded in processes, holding years of critical data, powering workflows that would take enormous effort to migrate.
The Oracle 10g database contained financial transactions, employee records, student-related data, and years of operational history. It didn't need replacing. It needed a bridge.
The instinct was to use modern drivers — Node.js, Python, PHP, different Oracle clients, downgraded runtimes. Each combination failed in a slightly different way.
The real breakthrough: instead of making modern tools speak Oracle, use Oracle's own native tool as the communication layer.
Modern apps talk HTTP. The gateway receives, validates, translates, and returns clean JSON — while SQL*Plus handles Oracle communication natively.
SQL*Plus is native to Oracle. It understands Oracle. For a legacy Oracle 10g system, that matters more than elegance. The gateway wraps it in a modern API.
Instead of wrestling with driver compatibility, the API executes SQL through Oracle's own native command-line tool. SQL*Plus handles authentication, session management, and result formatting — natively.
The FastAPI service builds the SQL*Plus input script, pipes it through subprocess, captures the output, and parses it into clean JSON. No Oracle client libraries needed at the Python level.
If SQL*Plus can connect, the API can connect — and SQL*Plus always knows how to talk to Oracle 10g.
The gateway exposes specific, validated business operations — not a raw SQL interface. Each endpoint represents a meaningful action: inserting a financial transaction, reading employee records, checking table structure.
Operations are scoped to business intent, with type validation, encoding rules, and audit logging built in at each endpoint.
Read operations, inserts, deletes, updates, and workflow automations can all be added as structured endpoints without ever exposing the underlying SQL engine.
Three critical pieces work together: subprocess execution, NLS environment alignment, and the Arabic CHR() encoding that preserves data integrity across character sets.
# FastAPI receives request → builds SQL*Plus script → executes def execute_sqlplus(self, sqlplus_script: str, timeout: int = 30): env = os.environ.copy() env["NLS_LANG"] = self.nls_lang # "ARABIC_AMERICA.AR8MSWIN1256" result = subprocess.run( ["sqlplus", "-S", self.connection_string], input=sqlplus_script.encode(self.sqlplus_encoding), capture_output=True, timeout=timeout, env=env, ) if result.returncode != 0: raise DatabaseError(result.stderr.decode("utf-8", errors="replace")) return self.parse_sqlplus_output( result.stdout.decode(self.sqlplus_encoding, errors="replace") )
The database uses AR8MSWIN1256 — Oracle's legacy Arabic character encoding, mapped to Windows cp1256. Modern applications work in Unicode. Bridging these without corrupting data required careful design.
Simply sending Unicode wasn't an option. The existing data was stored in cp1256. A Unicode insert would produce rows that look correct in some tools and broken in others — silent corruption.
The solution: align the SQL*Plus session with the database's NLS character set, then encode every Arabic string as CHR() byte expressions before sending. The database never sees Unicode — it sees its own native encoding.
If input arrives as mojibake (ت...), the API detects and repairs it first, then re-encodes through the correct cp1256 path.
Once an API can insert, delete, or modify records in a legacy Oracle system, it is not a convenience layer — it is a gate into sensitive production data.
The Oracle 10g gateway isn't just a connectivity solution. It's a compatibility layer between two worlds — one that speaks HTTP and JSON, one that speaks SQL*Plus and AR8MSWIN1256.
By respecting the database's existing storage model, enforcing security at every layer, and exposing controlled business operations rather than raw SQL, the gateway transformed an isolated legacy system into a programmable backend any modern application can safely consume.