A command-line tool for reviewing SQL statements against configurable rules. This tool helps ensure SQL code quality and consistency across different database engines.
- Complete MySQL Support: 92 comprehensive rules covering naming conventions, schema constraints, and statement analysis
- Complete PostgreSQL Support: 55 comprehensive rules for PostgreSQL best practices and standards
- Schema.yaml Integration: Default rule configurations with automatic payload generation
- Flexible Configuration: Support for both config/schema.yaml defaults and custom YAML/JSON config files
- Multiple Output Formats: Clean text, structured JSON, and YAML output options
- ANTLR-based Parsing: Robust SQL parsing with detailed error reporting and line/column information
- Consistent Error Handling: Syntax errors are converted to actionable advice with position information across all database engines
- Zero-config Operation: Works out-of-the-box with sensible defaults for MySQL and PostgreSQL
- Extensible Architecture: Modular design supporting easy addition of new database engines and rules
# Clone the repository
git clone https://github.com/NSXBet/sql-reviewer.git
cd sql-reviewer
# Build the CLI
go build -o sql-reviewer main.gogo get github.com/nsxbet/sql-reviewerSQL Reviewer can be used as a Go library in your applications. This is the recommended approach for integrating SQL validation into your codebase.
package main
import (
"context"
"fmt"
"log"
"github.com/nsxbet/sql-reviewer/pkg/reviewer"
"github.com/nsxbet/sql-reviewer/pkg/types"
)
func main() {
// Create a reviewer for MySQL or PostgreSQL
r := reviewer.New(types.Engine_MYSQL)
// r := reviewer.New(types.Engine_POSTGRES) // For PostgreSQL
// Review SQL statements
sql := "CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(100));"
result, err := r.Review(context.Background(), sql)
if err != nil {
log.Fatal(err)
}
// Check results
fmt.Printf("Found %d issues\n", result.Summary.Total)
if result.HasErrors() {
for _, advice := range result.FilterByStatus(types.Advice_ERROR) {
fmt.Printf("ERROR: %s\n", advice.Content)
}
}
}- High-level API: Simple
reviewer.New()andReview()methods - Low-level API: Direct access to
advisor.Check()for advanced use cases - Context support: Full support for cancellation and timeouts
- Custom configuration: Load rules from YAML/JSON or configure programmatically
- Schema-aware validation: Validate against existing database schema
- Result filtering: Easy filtering by severity, error code, etc.
See pkg/README.md for complete library documentation including:
- API reference and examples
- Configuration guide
- Schema-aware validation
- Custom rule implementation
- CI/CD integration patterns
Complete working examples are available in examples/library-usage/:
- basic/ - Simple usage with defaults
- with-config/ - Custom configuration
- with-schema/ - Schema-aware validation
- filtering/ - Advanced result processing
# Check a SQL file with default MySQL rules
./sql-reviewer check -e mysql examples/test.sql
# Enable debug output to see detailed rule processing
./sql-reviewer check -e mysql examples/test.sql --debug
# Output results in JSON format
./sql-reviewer check -e mysql -o json examples/test.sql# Check a SQL file against MySQL rules (uses config/schema.yaml defaults)
./sql-reviewer check -e mysql migration.sql
# Check with custom rules configuration
./sql-reviewer check -e mysql -r custom-rules.yaml migration.sql
# Check PostgreSQL with JSON output
./sql-reviewer check -e postgres -o json schema.sqlThe tool supports two configuration approaches:
The tool includes a comprehensive config/schema.yaml file with default rule configurations. No additional setup required:
# Uses built-in config/schema.yaml automatically
./sql-reviewer check -e mysql your-file.sqlCreate a custom rules configuration file in YAML format:
id: "custom-mysql-rules"
rules:
- type: "naming.table"
level: "ERROR"
engine: "MYSQL"
payload:
format: "^[a-z][a-z0-9_]*$"
maxLength: 63
- type: "statement.select.no-select-all"
level: "WARNING"
engine: "MYSQL"
payload: {}
- type: "table.require-pk"
level: "ERROR"
engine: "MYSQL"
payload: {}Provide database schema information in JSON format to enable advanced schema-aware checks:
{
"name": "mydb",
"schemas": [
{
"name": "public",
"tables": [
{
"name": "users",
"columns": [
{
"name": "id",
"type": "INTEGER",
"nullable": false
},
{
"name": "email",
"type": "VARCHAR(255)",
"nullable": false
}
]
}
]
}
]
}Usage with schema file:
./sql-reviewer check -e mysql --schema db-schema.json migration.sql--config: Configuration file path--verbose: Enable verbose output--debug: Enable debug output (shows rule processing details)
-e, --engine: Database engine (mysql,postgres)-o, --output: Output format (text,json,yaml)-r, --rules: Path to custom rules configuration file--schema: Path to database schema file (JSON)--fail-on-error: Exit with non-zero code if errors are found--fail-on-warning: Exit with non-zero code if warnings are found
./sql-reviewer check -e mysql migration.sql./sql-reviewer check -e mysql -r custom-rules.yaml --schema db-schema.json migration.sql# Fail the build if any errors are found
./sql-reviewer check -e mysql --fail-on-error migration.sql
# JSON output for parsing by other tools
./sql-reviewer check -e mysql -o json migration.sql | jq '.advices[] | select(.status == "ERROR")'- MySQL (
mysql) - ✅ Complete implementation (92 rules) - PostgreSQL (
postgres,postgresql) - ✅ Complete implementation (55 rules)
The tool supports comprehensive SQL review rules organized into categories:
Click to expand MySQL rules
- Table naming patterns
- Column naming patterns
- Index naming (UK, IDX, FK)
- Auto-increment column naming
- Identifier keyword restrictions
- Required columns and primary keys
- Column constraints (NOT NULL, DEFAULT, etc.)
- Data type restrictions and limits
- Character set and collation requirements
- Index and foreign key constraints
- SELECT statement best practices
- WHERE clause requirements and restrictions
- JOIN limitations and performance rules
- DML/DDL operation constraints
- Transaction and execution limits
- MySQL storage engine requirements (InnoDB)
- Character set and collation allowlists
- System object creation restrictions
- Performance and optimization rules
- Table naming patterns with regex support
- Column naming patterns
- Index naming conventions (PK, UK, FK, IDX)
- Fully qualified object names
- DROP TABLE naming patterns
- Table and column comment requirements
- Required columns enforcement
- NOT NULL constraints
- Default value requirements
- Column type change restrictions
- Disallowed column types
- Maximum character length limits
- Volatile default value restrictions
- Auto-increment constraints (PostgreSQL SERIAL types)
- Default values for NOT NULL columns
- No duplicate columns in indexes
- Index key number limits
- Primary key type restrictions
- Total index count limits
- Concurrent index creation requirements
- Primary key requirements
- Foreign key restrictions
- SELECT * restrictions
- WHERE clause requirements for SELECT/UPDATE/DELETE
- Leading wildcard LIKE restrictions
- INSERT column specification requirements
- INSERT row count limits
- ORDER BY RANDOM() restrictions
- COMMIT statement restrictions
- LIMIT value constraints
- Merge ALTER TABLE recommendations
- ADD COLUMN with DEFAULT restrictions
- CHECK constraint NOT VALID requirements
- Foreign key NOT VALID requirements
- ADD NOT NULL restrictions
- Schema specification requirements
- Mixed DDL/DML restrictions
- Affected row limits
- Partitioned table restrictions
- ON DELETE CASCADE restrictions
- DROP TABLE CASCADE restrictions
- Character set allowlists
- Collation allowlists
- DML dry-run validation
- Prior backup checks
- Non-transactional statement detection
- SET ROLE variable checks
- Object ownership validation
-- ❌ Fails naming.table rule
CREATE TABLE UserData (id INT);
-- ✅ Passes naming.table rule
CREATE TABLE user_data (id INT);
-- ❌ Fails table.require-pk rule
CREATE TABLE logs (message TEXT);
-- ✅ Passes table.require-pk rule
CREATE TABLE logs (id INT PRIMARY KEY, message TEXT);-- ❌ Fails naming.column rule
CREATE TABLE book (id INT, "creatorId" INT);
-- ✅ Passes naming.column rule
CREATE TABLE book (id INT, creator_id INT);
-- ❌ Fails statement.add-fk-not-valid rule
ALTER TABLE orders ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id);
-- ✅ Passes statement.add-fk-not-valid rule
ALTER TABLE orders ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id) NOT VALID;
-- ❌ Fails statement.select.no-select-all rule
SELECT * FROM users WHERE id = 1;
-- ✅ Passes statement.select.no-select-all rule
SELECT id, name, email FROM users WHERE id = 1;The tool follows a modular, extensible architecture:
sql-reviewer-cli/
├── cmd/ # CLI command implementations (Cobra)
├── pkg/
│ ├── advisor/ # Core rule engine and registration
│ ├── config/ # Configuration handling and schema.yaml
│ ├── rules/
│ │ ├── mysql/ # MySQL-specific rule implementations (92 rules)
│ │ └── postgres/ # PostgreSQL-specific rule implementations (55 rules)
│ ├── catalog/ # Database schema metadata handling
│ ├── mysqlparser/ # ANTLR-based MySQL SQL parser
│ ├── pgparser/ # ANTLR-based PostgreSQL SQL parser
│ ├── types/ # Shared type definitions
│ └── logger/ # Logging utilities
├── config/
│ └── schema.yaml # Default rule configurations
├── examples/ # Example configurations and SQL files
└── docs/ # Documentation
- ANTLR Parser: Robust SQL parsing with detailed AST analysis
- Rule Engine: Generic framework supporting multiple database engines
- Configuration System: Flexible YAML/JSON config with schema integration
- Payload Normalization: Automatic conversion between config formats
- Advisor Registration: Plugin-style rule registration system
See CLAUDE.md for comprehensive development guidelines.
For MySQL:
- Create rule implementation in
pkg/rules/mysql/ - Add test data in
pkg/rules/mysql/testdata/ - Register the rule in
pkg/rules/mysql/init.go - Update config/schema.yaml with default configuration
- Test thoroughly with various SQL patterns
For PostgreSQL:
- Create rule implementation in
pkg/rules/postgres/ - Add test data in
pkg/rules/postgres/testdata/ - Register the rule in
pkg/rules/postgres/init.go - Create test file in
pkg/rules/postgres/*_test.go - Test thoroughly with various SQL patterns
type TableCommentAdvisor struct {
*mysql.BaseAntlrRule
}
func (r *TableCommentAdvisor) Check(ctx context.Context, statements string, rule *types.SQLReviewRule, checkContext advisor.Context) ([]*types.Advice, error) {
res, err := mysql.ParseMySQL(statements)
if err != nil {
return nil, err
}
checker := &tableCommentChecker{rule: rule}
return mysql.NewGenericAntlrChecker(res.Tree, checker).Check()
}# Run all tests
go test ./...
# Run MySQL rule tests specifically
go test ./pkg/rules/mysql/
# Run PostgreSQL rule tests specifically
go test ./pkg/rules/postgres/
# Test with debug output (MySQL)
go run main.go check -e mysql examples/test.sql --debug
# Test with debug output (PostgreSQL)
go run main.go check -e postgres examples/postgres-test.sql --debug- Fork the repository
- Create a feature branch (
git checkout -b feature/new-rule) - Implement your changes following the patterns in CLAUDE.md
- Add comprehensive tests
- Update documentation as needed
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- PostgreSQL Engine: Complete PostgreSQL rule implementation (55 rules)
- Performance Optimization: Parallel rule execution
- Rule Management: CLI commands for listing and validating rules
- CI/CD Integration: GitHub Actions and pipeline examples
- VS Code Extension: IDE integration for real-time SQL review
- Additional Engines: Oracle, SQL Server, and Snowflake support
- PostgreSQL Advanced Rules: Implement remaining 5 database-dependent rules