Creating Custom Checks
DDLCheck can be extended with custom checks to fit your organization's specific needs and database practices.
Custom Check Basics
A check in DDLCheck is a Python class that:
- Extends the
Checkbase class - Implements required properties (
id,description,severity) - Implements the
check_statementmethod to analyze SQL statements
Creating a Custom Check
1. Create a New Python File
Create a new file for your custom check, either: - Inside the DDLCheck package (if contributing to the project) - In your own package or script (if extending for your specific use case)
2. Implement the Check Class
Here's a template for a custom check:
"""Custom check for something specific to your organization."""
from typing import Any, Dict, List
from ddlcheck.core import Check
from ddlcheck.models import Issue, SeverityLevel
class MyCustomCheck(Check):
"""Check for something specific to your organization."""
@property
def id(self) -> str:
"""Return the unique identifier for this check."""
return "my_custom_check"
@property
def description(self) -> str:
"""Return a description of what this check looks for."""
return "Detects something specific to your organization"
@property
def severity(self) -> SeverityLevel:
"""Return the default severity level for issues found by this check."""
return SeverityLevel.MEDIUM
def check_statement(self, stmt: Dict[str, Any], line: int) -> List[Issue]:
"""Check a single SQL statement for issues.
Args:
stmt: The parsed SQL statement
line: The line number where the statement begins
Returns:
List of issues found in the statement
"""
issues = []
# Implement your custom check logic here
# Example: Check if a statement contains a specific table
# if "some_condition":
# issues.append(
# self.create_issue(
# message="Message describing the issue",
# line=line,
# suggestion="Suggestion for how to fix it",
# )
# )
return issues
3. Register Your Custom Check
To use your custom check with DDLCheck, you need to register it in one of the following ways:
Option 1: Extend the checks module
If you're contributing to DDLCheck itself, add your check to the ALL_CHECKS list in src/ddlcheck/checks/__init__.py:
from ddlcheck.checks.my_custom_check import MyCustomCheck
# List of all available checks
ALL_CHECKS = [
# ... existing checks ...
MyCustomCheck,
]
Option 2: Use a plugin system (future feature)
In the future, DDLCheck may support a plugin system to load custom checks without modifying the core code.
Option 3: Create a custom entry point
You can create your own script that imports DDLCheck and registers your custom checks:
#!/usr/bin/env python
from ddlcheck.cli import app
from ddlcheck.checks import ALL_CHECKS
from my_module.my_custom_check import MyCustomCheck
# Add your custom check
ALL_CHECKS.append(MyCustomCheck)
if __name__ == "__main__":
app()
SQL Statement Structure
The stmt parameter passed to check_statement is a dictionary representation of the parsed SQL AST (Abstract Syntax Tree) using the pglast library.
The structure varies based on the statement type:
- The key is the statement type (e.g.,
"SelectStmt","AlterTableStmt","CreateIndexStmt") - The value is the parsed statement object with properties specific to that statement type
To understand the statement structure for your custom check, it can be helpful to:
- Use print debugging:
print(stmt)to see the full structure - Check existing checks for similar SQL statements
- Refer to the PostgreSQL parser source code for detailed node definitions