Usage

Blocking a destructive statement

from sql_query_tagger import SQLClassifier

classifier = SQLClassifier(engine="mysql", version="8.0")
result = classifier.classify_query("SELECT 1; DROP TABLE users;")

print(result.security_analysis.risk_level)         # RiskLevel.CRITICAL
print(result.security_analysis.is_suspicious)      # True
print(result.security_analysis.detected_patterns)
# ['stacked_queries_multiple_statements', 'stacked_queries_dangerous_followup', ...]

Engine-specific dangerous function

classifier = SQLClassifier(engine="sqlserver", version="2022")
result = classifier.classify_query("EXEC xp_cmdshell 'dir'")

print(result.security_analysis.engine_specific_risks)
# ['dangerous_function_xp_cmdshell']

Classifying query type only

classifier = SQLClassifier(engine="postgresql", version="16")

for sql in ["CREATE TABLE t (id INT)", "INSERT INTO t VALUES (1)", "SELECT * FROM t"]:
    result = classifier.classify_query(sql)
    print(sql, "->", result.query_type)
# CREATE TABLE t (id INT) -> QueryType.DDL
# INSERT INTO t VALUES (1) -> QueryType.DML
# SELECT * FROM t -> QueryType.DQL

Handling invalid input and unknown engines

from sql_query_tagger import SQLClassifier, UnsupportedEngineError

try:
    classifier = SQLClassifier(engine="db2", version="11.5")
except UnsupportedEngineError as e:
    print(f"Unsupported engine: {e}")

classifier = SQLClassifier(engine="postgresql", version="16")
try:
    classifier.classify_query("")
except ValueError as e:
    print(f"Invalid query: {e}")

Performance and caching

classify_query memoizes its security analysis and query-type classification per SQLClassifier instance, keyed by the cleaned query text (the part that calls into sqlglot and runs the regex scans). Tune or disable it with SQLClassifier(..., analysis_cache_size=N) (0 disables caching).

Run the benchmark yourself:

python benchmarks/bench_classify.py

Limitations

  • Static analysis only — it inspects query text, not a live schema, so it cannot tell you whether referenced tables/columns exist.

  • The stacked-query check splits on ; without parsing string literals, so a benign query containing a semicolon inside a string (e.g. 'a; b') may be flagged as multiple statements. Treat the risk score as a signal, not a verdict.