Everyone above you wants to "just ask the database questions." Raw text-to-SQL fails on real schemas, RAG can leak across tenants, and an ungoverned MCP server is a SQL injection surface with good manners. This module builds the versions that work: curated scopes, measured accuracy, RLS-inherited retrieval, and guardrails you can defend.
The demand is legitimate: business users want answers without a ticket queue, org assistants want a SQL surface, incident copilots want schema access. The DBA's job is not to say no — it is to design the blast radius. This module covers the three access patterns you will be asked to enable — natural-language SQL, retrieval over database content, and MCP servers for AI assistants — and the governance that makes each deployable: eval sets before rollout, entitlements enforced in the engine, and guardrails that assume the caller is confused at best.
Deepak is a database developer at a Gurugram consumer-lending company. A VP hears a text-to-SQL demo at a conference; two weeks later Deepak has a pilot: an LLM with schema access on a read replica, a chat UI, twelve business users.
A regional manager asks: "what was our disbursal total for July in the North region?" The system generates clean SQL, runs it, and returns ₹4.31 crore. Nobody doubts a number with decimals.
It summed loan_amount from the loans table filtered by region = 'North' and created_at in July. Plausible. Wrong three ways: disbursal lives in disbursements (loans can be approved but undisbursed), July should be the disbursal date, and cancelled loans carry a status the query never checked.
Finance reconciles month-end at ₹3.68 crore. The pilot's number had already gone into a regional review deck. The pilot is paused — by the VP who commissioned it.
Nothing "failed": the model wrote syntactically perfect SQL over the schema it saw. The schema was simply full of meaning nobody wrote down — status semantics, date-column semantics, which table is authoritative. Raw schemas do not carry meaning; that is why raw text-to-SQL fails on them.
The rescue, over the following month, is this module in miniature: curated semantic views that encode the business rules (v_disbursals with status and date logic baked in), a scoped role that can only see those views, an eval set of 25 real questions with known-correct answers, execution accuracy measured before and after curation — and refusal behavior for questions the views cannot answer. Accuracy on the eval set went from "we think it's usually right" to a number that could be defended, and improved with every view iteration.
Vendor NL surfaces follow the same discipline: Oracle Select AI takes a scoped profile (allowed tables, chosen LLM) — evaluate its accuracy on your schema before enabling it for anyone; SSMS Copilot's NL query is a DBA-facing convenience whose output you read before you run, same as any assistant. Evaluation before enablement, not after the first wrong number reaches a deck.
Whatever sits on top — NL-to-SQL, RAG, MCP — the engine-side controls are one stack:
| Layer | Control | What it stops |
|---|---|---|
| Placement | Read replica, never the primary | Runaway analytical queries degrading OLTP |
| Identity | Dedicated read-only role per AI surface | Any write, ever; clean audit attribution |
| Scope | Grants on curated views/schemas only; system catalogs and PII tables blocked | Schema snooping, off-limits data in scope |
| Cost | Statement timeout, row limits, work-mem caps | The 45-minute accidental cross join |
| Row entitlements | RLS/VPD/FLS enforced in-engine on the caller's identity | Cross-tenant and cross-region leakage |
| Evidence | Audit log of every AI-issued query | "What did the AI run?" answerable, always |
The design habit: assume the layer above will fail. The prompt will be injected, the model will generate something weird, the app will pass the wrong tenant ID. Each engine-side layer holds independently — that is why entitlements live in RLS and not in a WHERE clause the model is asked to include.
A WHERE clause in a prompt is a suggestion; a row-level security policy is a law. Any retrieval or NL-SQL design where tenant isolation depends on the model remembering to filter is a leak with a delay timer. Entitlements are enforced by the engine on the caller's identity — the model never holds the keys.
Module 4 built vector search in the engine; the governance question is who retrieves what. If support tickets are embedded and searchable, tenant A's semantically relevant results must never include tenant B's tickets — and the only trustworthy enforcement is the same row-level security the relational data already obeys. Engine-side retrieval makes this natural: the vector query is still SQL, so it runs as the caller (SET ROLE / session context per request — not a super-role connection pool that flattens identity), and RLS/VPD filters the candidate rows before similarity ranking.
Then prove it hostilely. An RLS-safe design is a claim; adversarial leak probes are the evidence:
MCP is how AI assistants and agents get tool access to your database, and it will arrive with or without you — better it arrives through a server you configured. Threat-model it as what it is: a programmatic SQL surface whose caller is a language model that can be socially engineered by any document it reads.
analytics schema views only — base tables refusedpg_catalog metadata limited; pg_authid, auth tables blockedThe server enforces what the model cannot promise.
The same read-only MCP pattern, pointed at monitoring APIs instead of table data, gives you natural-language fleet operations — "which instances grew 10% this month and why" — with one addition: a curated metric vocabulary. Define the metrics, their units, and their meaning in the resources the assistant sees; an assistant guessing what "growth" means across forty instances produces confident nonsense, the same disease as raw text-to-SQL, cured by the same curation.
Give every AI surface its own database role — nlsql_reader, rag_retrieval, mcp_assistant — never a shared one. Per-surface roles turn the audit log into an attribution record, let you revoke one surface without killing the others, and make "what can the AI see?" a \dp query instead of a meeting.
Every pattern above leans on the same scarce resource: written-down meaning. Semantic views encode it; eval sets test it; a data dictionary is its cheapest broad form — and AI now removes most of the drafting cost. Generate table and column descriptions from names, constraints, sampled values, and how app code actually uses the columns; then a human verifies business meaning before publication — the model can infer that status_cd is an enum, but only the org knows code 7 means "written off, pre-2019 rules." Wrong documentation is worse than none: every downstream AI surface inherits the error at generation speed. Verified, published, and fed back into NL-SQL prompts and MCP resources, the dictionary compounds: better docs make every AI answer over your data better.
Rollout order matters. Data dictionary → semantic views → eval set → scoped NL-SQL for a small pilot group → MCP for internal assistants — each step's artifact feeds the next, and accuracy numbers from the eval set gate each widening of the audience.
Check yourself: Security asks: "If the org assistant's MCP access were compromised by prompt injection tomorrow, what is the worst case?" Walk the guardrail stack and state the honest answer — and the one residual risk that remains.
This module anchors LAB-09 (guardrailed NL-to-SQL with an eval scorecard) — accuracy measured before and after semantic-view curation, with seeded ambiguous questions that must refuse — and LAB-10 (RLS-safe RAG and MCP leak test), where two seeded policy gaps must be found before all ten probes block. Do it at work this week → pb-33 (text-to-SQL on a replica), pb-34 (MCP guardrails), pb-35 (RLS-safe retrieval), pb-36 (NL fleet monitoring), and pb-27 (the verified data dictionary).
Governed AI access is layered: curated views give the model a schema worth querying, eval sets turn accuracy into a number that gates rollout, RLS makes entitlements physics instead of prompt hygiene, and MCP guardrails assume the caller can be fooled. The DBA who designs that blast radius is the reason the org gets to say yes.