Skip to content

How it works

  your test
      │
      ▼
  code under test ── JPA / Hibernate / MyBatis / jOOQ / JdbcTemplate / raw JDBC
      │
      ▼  SQL
  ┌──────────────────────────────┐
  │ QueryFence DataSource proxy  │  records SQL + call site (StackWalker)
  └──────────────┬───────────────┘
                 │ SQL passes through unchanged
                 ▼
             database

  after each test:
  captured SQL ──► parse (JSqlParser) ──► check rules ──► FAIL / REPORT
                                                          console + report.json

Capture

A DataSource proxy records every statement the driver executes, including each statement of a JDBC batch and statements that failed while executing. The SQL is passed on unchanged: QueryFence observes, it never rewrites or blocks.

A statement the driver rejects while preparing it never reaches the proxy, so it cannot be checked — that test fails on its own anyway.

Origin

StackWalker walks the stack at the moment of execution and takes the first frame that is not the JDK, a driver, an ORM, a framework or QueryFence itself. That is the method that wrote the query — com.acme.order.OrderRepository#findByStatus (OrderRepository.java:42) — not the framework that executed it. Naming your own packages with CaptureSettings.ofBasePackages("com.acme") makes the result exact.

Check

Statements are parsed once (JSqlParser) and cached by SQL string, then each rule walks the parsed statement: every occurrence of a protected table, in joins, subqueries, CTEs, each UNION branch, UPDATE/DELETE targets and INSERT ... SELECT sources.

Fail closed. Anything QueryFence cannot prove safe is reported: SQL that does not parse, a statement type it does not analyse yet, a predicate it cannot bind to a table.

Report

Findings are grouped per policy, printed at the end of the run and written to target/queryfence/report.json, each with the SQL, the rule, the fix and the origin. See CI for what to do with the file.

For the exact semantics — what counts as a predicate, how AND/OR compose, which ON clauses fence which table — read the design notes.