Member Junction
    Preparing search index...
    • Read-only enforcement for the native-query path (RunNativeQuery).

      External Data Sources are read-only by contract, but a stored Query's fully-rendered SQL is executed verbatim on a read/write connection. The provider-layer write backstop and ReadOnlyExternalBaseEntity only cover Save/Delete — they do NOT see this path — so the guarantee is enforced HERE, at the driver/engine boundary, not delegated to a caller.

      Fail-closed. Throws when the SQL:

      • contains multiple/stacked statements (injection / smuggled write),
      • cannot be parsed/validated in its dialect (can't prove it's read-only → refuse),
      • contains any write/DDL statement (INSERT/UPDATE/DELETE/MERGE/DROP/EXEC/CALL/… — HasWriteStatement; unparseable data-modifying CTEs are refused by the parse gate above), or
      • is a SELECT ... INTO <newtable> — it parses as a select (so HasWriteStatement is false), but it CREATES a table as a side effect, so it's caught here via StatementKind, or
      • starts with a DCL verb (GRANT/REVOKE/DENY), after leading comments/whitespace are stripped — a backstop because the underlying parser doesn't reliably surface these as a write type per-dialect.

      Known limitation — defense-in-depth, NOT a substitute for a least-privilege source credential:

      • A side-effecting routine invoked from a read shape (SELECT writing_func(), SELECT nextval('s')) is indistinguishable from a pure read in the AST and is NOT blocked. Configure External Data Sources with a read-only/least-privilege credential as the real authority; this screen is the app-level backstop against the common write/DDL/injection vectors.

      Parameters

      Returns void