> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qwedai.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# SQL engine

> QWED's SQL Engine validates queries for injection attacks, destructive operations, schema compliance, and syntax errors before execution in production.

<Info>
  **Updated in v7.0.0 (breaking).** `SQLVerifier.verify_sql()` now returns a [`DiagnosticResult`](/advanced/diagnostics) instead of an ad-hoc dict, and a proven-malicious query is reported as `VERIFIED` (truth) with a separate admission decision (policy). See the [changelog](/changelog#v7-0-0-—-full-diagnosticresult-engine-conformance) for migration details.
</Info>

SQL query validation and injection detection.

## Overview

The SQL Engine validates queries for:

* SQL injection patterns
* Destructive operations
* Schema compliance
* Syntax correctness

Verification is static AST analysis (SQLGlot). The engine never connects to a database.

## The `DiagnosticResult` contract

`verify_sql()` returns a `DiagnosticResult` with a status, an agent-safe `agent_message`, structured `developer_fields`, and a `proof_ref` bound to the query AST:

| Outcome | `status` | `developer_fields` | `proof_ref` |
| - | - | - | - |
| Safe query | `VERIFIED` | `is_valid: true` | Present |
| Malicious query | `VERIFIED` (as-malicious) | `is_valid: false`, `malicious_classification: true` | Present |
| Table outside `schema_ddl` | `BLOCKED` | `is_valid: false`, `constraint_id: "sql_verifier.schema_violation"` | `null` |
| Complexity limit exceeded | `BLOCKED` | `constraint_id: "sql_verifier.complexity_limit_exceeded"` | `null` |
| DDL schema parse failure | `BLOCKED` | `constraint_id: "sql_verifier.schema_parse_error"` | `null` |
| Query parse error | `BLOCKED` | `constraint_id: "sql_verifier.parse_error"` | `null` |
| Internal error | `BLOCKED` | `constraint_id: "sql_verifier.execution_error"` | `null` |

Proving that a query is malicious is a successful proof, so a malicious query is `VERIFIED` — not `BLOCKED`. `BLOCKED` is reserved for cases where verification itself could not complete, and blocked results never carry a `proof_ref`. If the DDL schema fails to parse, the incomplete analysis is `BLOCKED` even when the query itself looks malicious (`schema_parse_error` takes precedence).

`agent_message` never leaks detection rules, rule IDs, or raw parser output. Rule-level detail lives in `developer_fields`.

### Admission is a separate decision

Do not gate execution on `status` alone. `POST /verify/sql` returns an explicit `admission` field (`ADMIT` or `BLOCKED`) alongside the verdict. A malicious query is `VERIFIED` at the truth layer but `BLOCKED` at the admission layer. Gate on `admission` (or `developer_fields.is_valid`), never on `status == "VERIFIED"`.

## Usage

```python theme={null}
result = client.verify_sql(
    query="SELECT * FROM users WHERE id = 1",
    schema_ddl="CREATE TABLE users (id INT, name TEXT)"
)
print(result.status)                            # "VERIFIED"
print(result.developer_fields["is_valid"])      # True
print(result.proof_ref)                         # "sha256:..."
```

## Schema compliance

When you pass `schema_ddl`, every table the query reads or writes must be declared in that DDL. A reference to an undeclared table is an admission failure: the result is `BLOCKED` with `is_valid: false` and `constraint_id: "sql_verifier.schema_violation"`. Names the query defines itself, such as CTEs, are not treated as tables. Without `schema_ddl`, the engine does not check table names.

```python theme={null}
import httpx

try:
    result = client.verify_sql(
        query="SELECT * FROM payments",
        schema_ddl="CREATE TABLE users (id INT, name TEXT)",
    )
except httpx.HTTPError as exc:
    # Request failed (network error or non-2xx). Fail closed: do not run the SQL.
    raise RuntimeError(f"SQL verification unavailable: {exc}") from exc

print(result.status)                               # "BLOCKED"
print(result.developer_fields["is_valid"])         # False
print(result.developer_fields["constraint_id"])    # "sql_verifier.schema_violation"
```

<Note>
  Before v7.2.3, a query on a table outside the schema was admitted with a warning. See [GHSA-q5g6-6cw2-cjm3](https://github.com/QWED-AI/qwed-verification/security/advisories/GHSA-q5g6-6cw2-cjm3).
</Note>

## MySQL and MariaDB executable comments

MySQL and MariaDB run SQL placed inside executable comments (`/*! ... */`, `/*!NNNNN ... */`, and `/*M! ... */`). The SQL engine expands these comments before analysis, so injection, destructive-operation, and schema checks apply to the SQL inside them. The engine expands them whatever `dialect` you declare.

`developer_fields.executable_comments_expanded` is `true` when the query contained an executable comment.

```python theme={null}
import httpx

# The tautology hidden in the comment is analysed as SQL
try:
    result = client.verify_sql("SELECT * FROM users WHERE id = 1 /*!50000 OR 1=1 */")
except httpx.HTTPError as exc:
    # Request failed (network error or non-2xx). Fail closed: do not run the SQL.
    raise RuntimeError(f"SQL verification unavailable: {exc}") from exc
print(result.developer_fields["executable_comments_expanded"])  # True
print(result.developer_fields["is_valid"])                      # False
```

## Injection detection

```python theme={null}
# SQL injection pattern — proven malicious
result = client.verify_sql("SELECT * FROM users; DROP TABLE users; --")
print(result.status)                                            # "VERIFIED" (as-malicious)
print(result.developer_fields["is_valid"])                      # False
print(result.developer_fields["malicious_classification"])      # True
print(result.developer_fields["issues"])
# [{"severity": "CRITICAL", "issue_type": "injection", ...}]
```

## Detected patterns

| Pattern | Risk | Example |
| - | - | - |
| Comment injection | Critical | `; --` |
| OR injection | Critical | `' OR '1'='1` |
| UNION injection | Critical | `UNION SELECT` |
| Chained DROP | Critical | `; DROP TABLE` |

## Destructive operations

```python theme={null}
# Destructive query — verified, not valid, not admissible
result = client.verify_sql("DELETE FROM users")
print(result.developer_fields["is_valid"])   # False
print(result.developer_fields["issues"])
# [{"issue_type": "destructive_delete", "severity": "CRITICAL", ...}]
```

| Operation | Severity |
| - | - |
| DROP | Critical |
| DELETE | High |
| TRUNCATE | High |
| UPDATE | High |
| INSERT | High |
| ALTER | High |
| CREATE | High |
| MERGE | High |

### Administrative commands

The SQL engine also blocks administrative SQL commands by default:

| Command | Risk |
| - | - |
| GRANT | Critical |
| REVOKE | Critical |
| SET | Medium |
| TRANSACTION | Medium |

<Note>
  A resource-limit violation is a `CRITICAL` admission failure but not evidence of malicious intent. Only true-malice issue types set `malicious_classification: true`.
</Note>

## Supported dialects

* PostgreSQL
* MySQL
* SQLite
* SQL Server
* BigQuery

```python theme={null}
result = client.verify_sql(query, schema, dialect="postgresql")
```


## Related topics

- [Code engine](/engines/code.md)
- [Logic engine — Z3 SAT/SMT verification with QWED-Logic DSL](/engines/logic.md)
- [Changelog](/changelog.md)
- [Verification engine tiers: Proof, Policy, Advisory](/engines/overview.md)
- [API endpoints](/api/endpoints.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.