Skip to main content

QueryGuard SQL

QueryGuard SQL banner

PyPI version Python versions License GitHub repository

  • QueryGuard SQL is a small Python library for validating SQL before execution.

  • It is useful for LLM-generated SQL, NL2SQL apps, analytics assistants, and any workflow where SQL should be checked before it reaches the database.

Repository: github.com/WajeehAlamoudi/QueryGuard

Install

pip install queryguard-sql

Import package:

from queryguard import QueryGuard, GuardConfig

Quick Use

from queryguard import QueryGuard, GuardConfig

config = GuardConfig(
    database_type="mysql",
    allowed_tables=["users", "orders"],
    read_only=True,
    max_rows=100,
)

guard = QueryGuard(config)

result = guard.check("SELECT id FROM users")

print(result.allowed)
print(result.final_sql)
print(result.detected_tables)
print(result.errors)

Output:

True
"SELECT id FROM users LIMIT 100"
["users"]
[]

When To Use

Use QueryGuard SQL when you need to:

  • check SQL generated by an LLM
  • enforce read-only SQL
  • allow or block specific tables
  • validate columns using a schema
  • add safe row limits
  • suggest similar table names
  • inspect SQL before database execution

GuardConfig

GuardConfig defines the policy used by QueryGuard.

config = GuardConfig(
    database_type="postgres",
    allowed_tables=["public.users", "public.orders"],
    blocked_tables=["public.payments"],
    read_only=True,
    allow_select_star=False,
    max_rows=500,
    schema={
        "public.users": ["id", "name", "email"],
        "public.orders": ["id", "user_id", "total"],
    },
    suggest_tables=True,
    auto_fix_tables=False,
)

Parameters

Parameter Type Default Description
database_type str required SQL dialect, such as mysql, postgres, sqlite, bigquery, snowflake, tsql.
allowed_tables list[str] | None None Tables that may be queried. None means allow all tables unless blocked.
blocked_tables list[str] [] Tables that must always be blocked. This wins over allowed_tables.
read_only bool True Allows only read-only query types when enabled.
allow_select_star bool False Allows SELECT *. By default, SELECT * is blocked.
max_rows int | None 1000 Adds or lowers row limits. None disables limit rewriting.
schema dict[str, list[str]] | None None Known tables and allowed columns.
suggest_tables bool True Suggests similar known table names.
auto_fix_tables bool False Reserved for table auto-fix behavior. Prefer suggestions for now.

Table Rules

GuardConfig(
    database_type="mysql",
    allowed_tables=["users"],
)

Allowed:

SELECT id FROM users

Blocked:

SELECT id FROM payments

Schema-qualified table names are strict:

allowed_tables=["analytics.users"]

allows:

SELECT id FROM analytics.users

but not:

SELECT id FROM public.users

Schema Rules

If schema is provided, QueryGuard can validate selected columns.

GuardConfig(
    database_type="mysql",
    schema={
        "users": ["id", "name", "email"],
    },
)

Allowed:

SELECT id, name FROM users

Blocked:

SELECT password_hash FROM users

SELECT Star

By default, SELECT * is blocked.

SELECT * FROM users

To allow it, set:

GuardConfig(
    database_type="mysql",
    allow_select_star=True,
)

This remains allowed by default because it does not expose all columns:

SELECT COUNT(*) FROM users

Suggestions

Suggestions use known tables from allowed_tables or schema.

guard = QueryGuard(
    GuardConfig(
        database_type="mysql",
        allowed_tables=["users", "orders"],
        suggest_tables=True,
    )
)

result = guard.check("SELECT id FROM usres")

print(result.suggestions)

Output:

{"usres": ["users"]}

QueryGuard

QueryGuard receives a GuardConfig and uses it to validate SQL.

guard = QueryGuard(config)

Methods

Method Returns Description
check(sql, raise_on_blocked=False) GuardResult Full validation result.
validate(sql) str Returns safe SQL or raises if blocked.
rewrite(sql) str Returns rewritten SQL or raises if blocked.
is_safe(sql) bool Returns True when SQL is allowed.
tables(sql) list[str] Returns detected table names.
check_many(sqls) list[GuardResult] Checks many SQL strings.
explain(sql) str Human-readable explanation.
set_policy(config) None Replaces the current config.

Example

result = guard.check("DELETE FROM users")

print(result.allowed)
print(result.errors)

Output:

False
["DELETE is not allowed in read_only mode"]

GuardResult

guard.check() returns a GuardResult.

result.allowed          # bool
result.original_sql     # str
result.final_sql        # str | None
result.database_type    # str | None
result.detected_tables  # list[str]
result.errors           # list[str]
result.warnings         # list[str]
result.suggestions      # dict[str, list[str]]

Example:

result = guard.check("SELECT id FROM users")

if result.allowed:
    db.execute(result.final_sql)
else:
    print(result.errors)

Supported Dialects

Common supported dialect names:

mysql
mariadb
postgres
postgresql
sqlite
bigquery
snowflake
duckdb
redshift
trino
presto
spark
tsql
sqlserver
mssql
oracle
clickhouse

QueryGuard SQL uses sqlglot for SQL parsing and generation.

Security Note

QueryGuard SQL validates SQL structure and configured policy before execution. It does not replace database permissions, parameterized queries, or least-privilege database users.

For production systems, always keep database-side protections enabled.

License

MIT License.

Metadata

Release files for queryguard-sql 0.1.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for queryguard-sql 0.1.5
File Size Uploaded
queryguard_sql-0.1.5.tar.gz 14.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for queryguard-sql 0.1.5
File Interpreter ABI Platform
queryguard_sql-0.1.5-py3-none-any.whl Python 3 none any Details

Total release size: 29.5 kB

Release files / queryguard_sql-0.1.5.tar.gz

Download URL queryguard_sql-0.1.5.tar.gz
Size 14.0 kB
Tags Source
SHA-256 checksum
How to use checksums
7a76e27413cf152ebdbabc7212d3462925b2c3698d14e46588f497dd9a2d2b7f
BLAKE2b-256 checksum
How to use checksums
9c7ad763e1a7622590fb8cca30f26ce178b0ec9a14a3894dea59d6cf6039592d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.6

Release files / queryguard_sql-0.1.5-py3-none-any.whl

Download URL queryguard_sql-0.1.5-py3-none-any.whl
Size 15.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a4b6987a220ca140d9389d5306bd66e5b16cca13072ae911df17880b52af1e10
BLAKE2b-256 checksum
How to use checksums
c80132aee002e11ea407513641d38411a92b5c0f7bcff5e4cf050eafcffcae84
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.6

Release history Release notifications | RSS feed

This release

0.1.5 This release

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page