Repository navigation
Releases: Levyks/dbsaci
Release list
v0.0.8
Session time zones, done the way Oracle does them.
What changed
ALTER SESSION SET TIME_ZONEaccepts a named IANA region
('America/Sao_Paulo'), a fixed offset ('-03:00'), or'local'.TIMESTAMPTZvalues are converted to the session zone on the wire — with
per-instant, DST-correct offsets for named regions — instead of coming back in
UTC. Views no longer needAT TIME ZONE/::timestampcasts, and the Oracle
JDBC thin driver no longer needsoracle.jdbc.timezoneAsRegion=false. PG
timestamp(no zone) is unchanged.SESSIONTIMEZONE,DBTIMEZONE(usable without parens),
SYS_CONTEXT('USERENV','SESSIONTIMEZONE' | 'DB_TIMEZONE').- Preflight also drops a stale
oracle.sys_contextleft by pre-0.0.5 builds,
which shadowed the currentpublic.sys_context.
Note
New chrono-tz dependency bundles the IANA time-zone database (pure Rust). The
image stays a static musl binary on scratch, now ~12 MB (was ~10).
New corpus group time_zones.sql (13 cases). corpus 664 → 675.
docker pull levyks/pgsaci:0.0.8
v0.0.7
Acting on an external review of pgSaci's drop-in experience.
Added
- Preflight diagnostics. On its first backend connection pgSaci logs a
one-time check of the target database: isorafceinstalled, what is the
effectivesearch_path, and does the login user's schema contain any
upper/mixed-case identifiers an Oracle client can't reach. A missing
assumption now shows up as one line, not an opaque PostgreSQL error later. - Session visibility.
GET /sessionson the health port returns a JSON
list of live Oracle sessions (id,addr,user,age_seconds);
DELETE /sessions/<id>aborts one — dropping its backend PostgreSQL
connection and releasing any locks it held. - Idle-reap timeout is logged at startup (default unchanged at 900s).
- Docs: Identifier case (use lower-case identifiers in the target schema),
Oracle JDBC thin driver (oracle.jdbc.timezoneAsRegion=false), and
Preflight diagnostics sections in getting-started.
Deliberately not done
- No distinctive "unsupported construct" error — pgSaci stays a best-effort
text rewriter. - No case-insensitive catalog identifier resolution — conflicts with the
stateless text-rewriter design and with Oracle semantics where"no"/"NO"
coexist; the preflight warning covers the real pain. - No
timestamptz -> DATEwire mode / TZ-region negotiation yet — touches
result encoding and drops tz precision; documented the workaround instead.
docker pull levyks/pgsaci:0.0.7 — digest sha256:6357a2787e75…, 9.77 MB.
v0.0.6
IDE schema browser: fill out the ALL_* data dictionary
DataGrip / IntelliJ (and SQL Developer, DBeaver) introspect a long tail of
Oracle dictionary views and abort on the first missing view or column. This
release widens the ones they read column-by-column and stubs the rest.
ALL_TABLES/ALL_INDEXES/ALL_TRIGGERS(and theirUSER_*views)
grow the full Oracle column set, appended soCREATE OR REPLACE VIEWaccepts
it.ALL_TRIGGERSnow derives real timing / event /BEFORE_ROWetc. from
pg_trigger.tgtypeand carriesACTION_TYPE.- New:
SYS.ALL_OBJECT_TABLES,ALL_MVIEW_LOGS,ALL_MVIEW_COMMENTS,
ALL_IND_EXPRESSIONS. - ~45 new
SYS.*stub views — partitioning / subpartitions, object types /
collections / methods, LOBs,ALL_TAB_IDENTITY_COLS(real, from
pg_attribute.attidentity), privileges, tablespaces / segments, scheduler /
jobs / queues, directories / libraries / java / clusters / operators /
indextypes, XML DB, editions, VPD policies, dimensions, optimizer stats &
histograms, PL/SQL settings, identifiers. Empty (no PostgreSQL equivalent) —
the point is only that aSELECTresolves instead ofORA-00942/ORA-00904. - Version / identity:
SYS.PRODUCT_COMPONENT_VERSION,
NLS_DATABASE_PARAMETERS,DATABASE_PROPERTIES,GLOBAL_NAME— plus
unqualified copies of the first three.
Known gap: SYS.ALL_SOURCE resolves but returns nothing.
docker pull levyks/pgsaci:0.0.6 — digest sha256:5108c80e80d8…, 9.77 MB.
v0.0.5
Schema == user
Every pgSaci user now owns a PostgreSQL schema of its own name, instead of its
objects landing in the shared oracle schema by search_path accident. The
catalog facade stops faking owners — an IDE shows your tables under your node
because the schema genuinely is yours.
- Connect:
CREATE SCHEMA IF NOT EXISTS "<user>"(best-effort — a backend
role withoutCREATEon the database still connects; objects then resolve via
oracle/publicand a warning is logged).search_path="<user>", oracle, public. publicis the shared fallback: unqualified names not in your schema
resolve there, andpublic.<name>always works — front an existing
PostgreSQL database whose tables live inpublicand it works unchanged.- Cross-schema access is a qualified name plus grants
(SELECT * FROM hr.emp);ALTER SESSION SET CURRENT_SCHEMA = hrredirects
unqualified resolution. - Facade reverts the 0.0.4
oracle → current_userworkaround — owners and
USER_*scoping are honest again.
New corpus group schemas.sql (11 cases). corpus 644 → 655.
docker pull levyks/pgsaci:0.0.5
v0.0.4
IDE schema browser: objects appear under the connected user
pgSaci keeps every user's objects in a shared PostgreSQL oracle schema. The
SYS.ALL_* / USER_* catalog facade was exposing that literally as owner
ORACLE, and sys.all_users never listed the login role — so DataGrip /
IntelliJ (which assume Oracle's "schema == user" model) showed no node for the
connected user and none of their tables.
all_*/user_*facade views now report objects in theoracleschema as
owned bycurrent_user;user_*filters follow the same mapping.sys.all_userslists the connected user; the per-package schemas orafce
creates (dbms_*,plv*,utl_file,plunit) are filtered out.- PostgreSQL 18 catalogues
NOT NULLaspg_constraint.contype = 'n'— mapped
to Oracleconstraint_type = 'C'with aNOT NULL <col>search condition
instead of leaking the raw'n'. dbms_metadata.get_ddl(type, name, schema): whenschemais the connected
user, resolve against theoracleschema.
Also in this line: CONNECT BY on NUMBER(p)-typed key columns (v0.0.3) —
the WITH RECURSIVE ancestor-path array had a typmod mismatch between the
union arms, breaking any hierarchy keyed on a precision-qualified NUMBER.
docker pull levyks/pgsaci:0.0.4 — digest sha256:5ffd5c107452…, 9.77 MB.
v0.0.3
Fixes
CONNECT BYonNUMBER(p)-typed key columns now translates. The
CONNECT BY→WITH RECURSIVElowering carries an ancestor-id path array for
cycle detection; the non-recursive arm kept the key column's typmod
(numeric(4,0)[]) while the recursive arm producednumeric[], and
PostgreSQL rejects a recursive union whose arms disagree on type. Any
hierarchy keyed on a precision-qualifiedNUMBER— i.e. most real Oracle
HR/ERP schemas — failed with
recursive query "__cb" column N has type numeric(4,0)[] .... Path-array
elements are now normalised totextin both arms. (5ba1bba)
Benchmarks
bench/run.shnow runs entirely in Docker on one bridge network (client,
Oracle XE, PostgreSQL, pgSaci), pgSaci from the published image, both engines
at 2 CPU / 2.5 GiB with Oracle spending its full 2 GiB licence and PostgreSQL
tuned to the envelope. Refreshed numbers in the README and docs. (f50f426)
Docker
docker pull levyks/pgsaci:0.0.3 — digest sha256:1217905bd2aa…, 9.77 MB
(static musl on scratch).
pgSaci 0.0.2
Alpha. Very early — do not point it at data you care about.
Container
docker pull levyks/pgsaci:0.0.2
~10 MB static-musl image on scratch. See the docs.
Since 0.0.1 — IDE schema-browser compatibility
DataGrip / IntelliJ (the reference client) now introspects a pgSaci connection end to end and can browse and query the schema tree.
SYS.ALL_*/SYS.USER_*data-dictionary facade overpg_catalog— tables, columns, objects, constraints, indexes, sequences, comments, triggers, users — returning UPPERCASE identifiers like a real Oracle database, so Oracle tooling stops seeingpublicandPUBLICas two schemas.DBMS_METADATA.GET_DDL(TABLE / VIEW / MATERIALIZED VIEW / INDEX / SEQUENCE / TRIGGER / FUNCTION) for the "copy DDL" action, rendered as PostgreSQL DDL. PlusDBMS_UTILITY.GET_HASH_VALUE,USER_TABLESPACES,sys.session_roles/session_privs.DECODEnow compares its operands as text — Oracle coerces them to one type; PostgreSQL's=does not, soDECODE(sys_context(...), 0, ...)no longer fails.- Translator: SELECT-list aliases now resolve inside
ORDER BYexpressions (ORDER BY decode(alias, ...)), matching Oracle.
Fixes
- Connect-storm deadlock. The catalog facade (
CREATE OR REPLACE VIEW, ACCESS EXCLUSIVE) was re-applied on every connect; an IDE client idle in a transaction would freeze a wave of new connections behind it. It's now applied once per deploy, guarded by a version marker and an advisory lock.
Verified
cargo test --lib 30/0 · --test corpus 638/0 · --test translate_golden · python-oracledb thin 31/31 · ODP.NET 13/13 · abstraction.mdc Spring/ojdbc suite 32/32.