Oracle Database access governance — every statement reviewed before it runs
Last updated
AccessFlow governs Oracle Database as a full query proxy: your team connects to AccessFlow, not to the database, and every statement is parsed, checked against a schema allow-list, risk-scored, routed to an approver, and only then executed — under column masking, row-level security and a row cap. The pipeline itself — parse, risk-score, route, approve, execute, audit — is the same for every relational engine and is described in full on the database access governance page. What follows is what is specific to Oracle Database.
- Family
- Relational
- Query language
- SQL
- Runs as
- In-process pooled JDBC
- Default port
1521- Default SSL mode
REQUIRE- Install
- One-click from the connector catalog
The driver and the connection
The Oracle driver is com.oracle.database.jdbc:ojdbc11, resolved from the connector catalog on first use. Oracle license terms apply to that driver — it is fetched from Oracle rather than redistributed by AccessFlow, and accepting those terms is your call to make, not something the installer can make for you.
The datasource takes host, port (1521 by default), the service or database name, username and password — AES-256-GCM encrypted at rest and decrypted exactly once at pool initialisation, or supplied as a Vault, AWS Secrets Manager or Azure Key Vault reference. SSL defaults to REQUIRE.
AccessFlow builds the connection string from the datasource fields using the template the connector manifest declares, so what actually reaches the driver is predictable and reviewable:
jdbc:oracle:thin:@//{host}:{port}/{database_name}
oracle.jdbc.OracleDriver
Drivers are resolved on demand — the first time a datasource of this type is created or tested — and each one gets its own classloader. Two datasources pointing at different driver versions, even two Oracle Database datasources, load disjoint copies and cannot interfere with each other through static state.
What AccessFlow parses
Statements are parsed to a syntax tree, and the schema allow-list is enforced against that tree — so an allow-list entry means a real table reference, not a string that happened to appear somewhere in the text. The parsed type decides which capability the caller needs and which approval chain applies.
What it refuses
Multi-statement input is refused, with the single exception of a BEGIN; … COMMIT; envelope wrapping a homogeneous write batch. Anything the parser cannot read is rejected with HTTP 422 before a connection is taken from the pool, so a malformed statement never reaches the database at all.
Row-level security and masking
A policy is spliced into the WHERE clause as a bound predicate. Joins, subqueries and set operations that cannot be provably narrowed are refused rather than executed unfiltered, and masks are applied to the result after fetch.
What the rewrite actually does
A policy restricting ledger_entries to the caller's cost centre narrows the statement before Oracle plans it:
-- submitted SELECT entry_id, amount FROM ledger_entries WHERE posted = 'N'; -- executed (policy: ledger_entries.cost_centre = the caller's cost centre) SELECT entry_id, amount FROM ledger_entries WHERE (posted = 'N') AND ledger_entries.cost_centre = ?;
The bound value is what makes this safe to do automatically. It also means the dry-run plans exactly this statement — predicate included — so the row estimate a reviewer sees is the estimate for the query that will actually run, not for the one that was typed.
Introspection, dry-run and cost estimates
Oracle is the one engine whose dry-run writes before it reads: EXPLAIN PLAN FOR stores the plan in Oracle's PLAN_TABLE, AccessFlow reads it back, and then deletes the rows it wrote in a finally block so a plan preview never leaves scratch state behind. Because the plan has to be written first, a dry-run of a write plans on the primary rather than on a read replica.