Skip to content

xenotik/translaterSQL

Repository files navigation

Конвертер диалектов SQL: Oracle ⇆ PostgreSQL

Библиотека на C++/Qt для автоматического перевода SQL‑диалектов между Oracle и PostgreSQL. Подходит для миграций, статического анализа и полуавтоматической конвертации DDL/DML в приложениях.

Возможности

  • Oracle → PostgreSQL и PostgreSQL → Oracle (двунаправленный перевод).
  • Регулярные выражения case‑insensitive, аккуратные границы слов — меньше ложных срабатываний.
  • Сохранение аргументов функций/типов: NUMBER(10,2) → NUMERIC(10,2), SUBSTR(s,2,5) → SUBSTRING(s FROM 2 FOR 5) и т. п.
  • Корректные соответствия распространённых конструкций:
    • NVL → COALESCE
    • DECODE(...) → CASE ... END (с поддержкой ELSE)
    • TO_NUMBER(...) → to_number(...)
    • TO_DATE(str, fmt) → to_date(...) | to_timestamp(...) (автоопределение по наличию HH/MI/SS)
    • TRUNC(date, 'unit') → date_trunc('unit', date) и обратно
    • INSTR(s, sub) ↔ POSITION(sub IN s)
    • Типы данных: NUMBER/NVARCHAR2/VARCHAR2/RAW/BLOB/CLOB/LONG/NCHAR/NCLOB/INTERVALNUMERIC/VARCHAR/BYTEA/TEXT/...
    • EXPLAIN PLAN FOREXPLAIN
    • SYSTIMESTAMP/SYSDATECURRENT_TIMESTAMP
  • Понятные подсказки там, где нужен ручной рефакторинг:
    • LEVEL, CONNECT BYWITH RECURSIVE — вставляются комментарии‑заглушки.
  • Опциональная вставка/удаление FROM DUAL:
    • Oracle: SELECT 1 FROM DUAL; → PostgreSQL: SELECT 1;
    • PostgreSQL: SELECT 1; → Oracle: SELECT 1 FROM DUAL;

Быстрый старт

Требования

  • C++17+
  • Qt 5.15+ или Qt 6.x (модули Core)

Использование

#include "translateSQL.h"
#include <QString>
#include <iostream>

int main() {
    translateSQL tr;

    QString sql = "SELECT NVL(name,'n/a'), TRUNC(hire_date,'MONTH') FROM dual";
    QString res = tr.translateString(sql, translateSQL::oracleToPostgres);
    std::cout << res.toStdString() << std::endl;
    // → SELECT COALESCE(name,'n/a'), date_trunc('month', hire_date)

    QString pg = "SELECT SUBSTRING(title FROM 5 FOR 3), POSITION('x' IN title);";
    QString res2 = tr.translateString(pg, translateSQL::postgresToOracle);
    std::cout << res2.toStdString() << std::endl;
    // → SELECT SUBSTR(title, 5, 3), INSTR(title, 'x');
}

Примечание про FROM DUAL:

  • В Oracle DUAL используется для выборки «из ниоткуда». В PostgreSQL FROM можно опускать.
  • В библиотеке предусмотрены правила для удаления FROM DUAL при переводе в PostgreSQL и добавления при обратном преобразовании у SELECT без FROM (в т. ч. после UNION/INTERSECT/EXCEPT). Их можно включить/выключить, оставив/закомментировав соответствующие правила в rulesO2P_ и rulesP2O_.

Поддерживаемые преобразования

Oracle → PostgreSQL (основные)

  • Типы:
    NUMBER(p,s) → NUMERIC(p,s)VARCHAR2(n [BYTE|CHAR]) → VARCHAR(n)NVARCHAR2(n) → VARCHAR(n)
    DATE(type) → TIMESTAMPBLOB → BYTEACLOB/LONG/NCLOB → TEXTRAW(n) → BYTEANCHAR(n) → CHAR(n)
    INTERVAL DAY TO SECOND|YEAR TO MONTH → INTERVAL
  • Функции:
    NVL(a,b) → COALESCE(a,b)DECODE(expr, s1, r1, [s2, r2]..., [else]) → CASE expr WHEN s1 THEN r1 ... [ELSE ...] END
    TO_NUMBER(x[, fmt]) → to_number(x[, fmt])
    TO_DATE(str, fmt) → to_date(str, fmt) (если есть HH/MI/SSto_timestamp(...))
    TRUNC(dt[, 'unit']) → date_trunc('unit', dt)
    SUBSTR(s, n[, m]) → SUBSTRING(s FROM n [FOR m])
    INSTR(s, sub) → POSITION(sub IN s)
    SYSTIMESTAMP|SYSDATE → CURRENT_TIMESTAMP
    EXPLAIN PLAN FOR → EXPLAIN
  • Иерархия:
    LEVEL, CONNECT BY → комментарии с подсказкой переписать на рекурсивный CTE.

PostgreSQL → Oracle (основные)

  • Типы:
    NUMERIC(p,s) → NUMBER(p,s)VARCHAR(n) → VARCHAR2(n)BYTEA → BLOBTEXT → CLOB
    INTERVAL → INTERVAL DAY TO SECONDTIMESTAMP [WITH/WITHOUT TIME ZONE] → TIMESTAMP[/WITH TIME ZONE]
  • Функции:
    COALESCE(a,b) → NVL(a,b) (только 2 аргумента; при 3+ лучше использовать COALESCE в Oracle)
    TO_TIMESTAMP(...) → TO_TIMESTAMP(...)
    DATE_TRUNC('unit', dt) → TRUNC(dt[, 'unit'])
    SUBSTRING(s FROM n [FOR m]) → SUBSTR(s, n[, m])
    POSITION(sub IN s) → INSTR(s, sub)
    CURRENT_TIMESTAMP → SYSTIMESTAMP
    EXPLAIN → EXPLAIN PLAN FOR
  • Без FROM:
    Вставка FROM DUAL в SELECT без источника (в начале оператора и после UNION/INTERSECT/EXCEPT).

Примеры запросов для проверки

Oracle → PostgreSQL

CREATE TABLE t_emp (
  id NUMBER(10),
  name VARCHAR2(100 CHAR),
  nick NVARCHAR2(40),
  hire_date DATE,
  photo BLOB,
  note CLOB,
  raw_col RAW(16),
  long_col LONG,
  nchar_col NCHAR(5),
  nclob_col NCLOB,
  dur INTERVAL DAY TO SECOND
);

SELECT SYSDATE, SYSTIMESTAMP FROM dual;
SELECT NVL(phone, 'n/a') AS p FROM t_emp;
SELECT DECODE(status, 'OK', 1, 'N/A, TBD', 0, -1) AS s FROM t_status;
SELECT TO_NUMBER('1,234.56', '9G999D99') AS v;
SELECT TO_DATE('2025-08-22','YYYY-MM-DD') d1,
       TO_DATE('2025-08-22 13:45','YYYY-MM-DD HH24:MI') d2;
SELECT TRUNC(hire_date, 'MONTH') m, TRUNC(hire_date) d FROM t_emp;
SELECT SUBSTR(name, 2, 5), SUBSTR(name, 3), INSTR(name, 'a') FROM t_emp;
SELECT LEVEL, id FROM t_tree CONNECT BY PRIOR id = parent_id START WITH parent_id IS NULL;
EXPLAIN PLAN FOR SELECT 1 FROM dual;

PostgreSQL → Oracle

CREATE TABLE t_doc (
  id NUMERIC(10,2),
  title VARCHAR(200),
  payload BYTEA,
  body TEXT,
  created_at TIMESTAMP,
  period INTERVAL
);

SELECT CURRENT_TIMESTAMP;
SELECT COALESCE(phone, 'n/a') FROM t_emp;
SELECT TO_TIMESTAMP('2025-08-22 12:34','YYYY-MM-DD HH24:MI');
SELECT DATE_TRUNC('day', created_at), DATE_TRUNC('month', created_at) FROM t_emp;
SELECT SUBSTRING(title FROM 5 FOR 3), SUBSTRING(title FROM 3), POSITION('x' IN title) FROM t_doc;
WITH RECURSIVE r(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM r WHERE n < 3) SELECT * FROM r;
EXPLAIN SELECT * FROM t_emp;
SELECT 1 UNION ALL SELECT 2; -- должно превратиться в ... FROM DUAL

Известные ограничения

  • Иерархические запросы Oracle (CONNECT BY, LEVEL) требуют ручной перекладки на рекурсивные CTE в PostgreSQL.
  • Расширенные формы INSTR с 3–4 аргументами пока не конвертируются (позиция/вхождение).
  • COALESCE с >2 аргументами лучше оставлять как есть при переводе в Oracle (Oracle его поддерживает; если нужно строго NVL — только для 2 арг.).
  • Форматы дат обрабатываются эвристикой: наличие HH/MI/SS трактуется как время → to_timestamp.
  • README описывает «модернизированную» версию класса. Если используется первоначальный вариант, часть возможностей может отсутствовать, обновите translateSQL.cpp/.h до актуальной версии.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published