An experimental parser and transpiler for a subset of Oracle SQL/PL-SQL, built in Rust using the Pest PEG parsing framework. This project was developed to investigate the feasibility of using declarative grammars for database schema migration and query translation.
This project has served its purpose as a technical proof-of-concept. The primary goal was to evaluate Pest for parsing SQL-like languages.
Key Finding: While Pest excels at tokenizing and parsing flat structures (DDL, simple DML), it presents significant challenges when handling deeply nested recursive expressions and complex PL/SQL blocks without becoming overly complex and hard to maintain.
Consequently, active development has been paused. The repository remains available as a reference implementation for AST design and basic type translation logic.
- Strengths of Pest: Highly effective for flat structures, tokenization, and standard DDL operations (
CREATE TABLE, basicSELECT). - Limitations Identified: Handling recursive nesting (subqueries, nested functions) requires excessively complex grammar rules that reduce maintainability.
- Architectural Validation: The separation of concerns into Parsing → AST → Translation proved to be a robust pattern for migration tools.
Despite the pause in development, the prototype successfully implements:
- Basic Operator Parsing:
SELECT,INSERT,UPDATE,DELETE, andCREATE TABLE. - Oracle Type Translation:
VARCHAR2→VARCHAR/TEXTNUMBER→NUMERIC/INTEGERDATE→TIMESTAMP
- Function & Syntax Normalization:
NVL(a, b)→COALESCE(a, b)SYSDATE→CURRENT_TIMESTAMP/NOW()- Automatic removal of
FROM DUALclauses.
- Rust: Chosen for memory safety and strict type checking of the AST.
- Pest: Used for defining the PEG grammar and lexical analysis.
- Regex: Employed for post-processing specific string patterns and function replacements.
use crate::ast_tree::{parse_everything};
use ast_tree::{Translate};
use ast_tree::DataBases;
mod ast_tree;
fn main() {
let string = "
CREATE TABLE orders (
id NUMBER,
description VARCHAR2(255),
created DATE,
amount NUMBER(10,2)
);";
let program = parse_everything(&string);
for stmt in program {
println!("{}", stmt.to_change(DataBases::Postgres))
}
}Output:
CREATE TABLE orders (id INTEGER, description VARCHAR(255), created TIMESTAMP, amount NUMERIC(10,2));This repository is useful for developers who:
- Are learning how to build parsers in Rust.
- Want to see a practical example of the Translator Pattern applied to SQL.
- Are evaluating PEG parsers (like Pest) and want to see a real-world example of their limitations with recursive structures.