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.