The Rule Interface
All pgvet rules implement theRule interface defined in rule/rule.go:24:
Methods
- Name(): Returns a kebab-case identifier for the rule (e.g.,
"select-star") - Description(): Returns a human-readable explanation of what the rule checks
- Check(): Analyzes a parsed SQL statement and returns diagnostics for any issues found
Diagnostic Structure
TheDiagnostic struct represents an issue found by a rule:
rule.SeverityWarning- Stylistic issues or suggestionsrule.SeverityError- Logical errors or dangerous patterns
AST Traversal with walker.Walk
For rules that need to inspect nested SQL structures (subqueries, CTEs, etc.), use thewalker.Walk helper from walker/walker.go:11:
Example: Simple Rule Without Traversal
Here’s theselect-star rule that checks only the outermost SELECT statement:
Example: Rule with AST Traversal
Thenot-in-subquery rule uses walker.Walk to find problematic patterns anywhere in the query:
Converting Byte Offsets to Line/Column
Nodes in the AST have aLocation field with a byte offset. Use offsetToLineCol to convert this to 1-based line and column numbers:
rule/util.go:4 and handles newline counting for you.
Registering Custom Rules
To use your custom rule:- Add it to the
All()function inrule/rules.gofor default rules - Or add it to
Extra()for opt-in rules that users must explicitly enable with--rules
Testing Your Rule
Create a test file following the pattern inrule/select_star_test.go. Test both positive and negative cases:
Learning More
The AST structure comes from PostgreSQL’s parser via pg_query_go. To understand the structure:- Use the pg_query parser demo to visualize SQL as protobuf
- Read the protobuf definitions
- Study existing pgvet rules in
rule/*.gofor common patterns