Skip to content

Commit 3d871ee

Browse files
ajitpratap0Ajit Pratap Singhclaude
authored
feat: Parser Enhancements Batch 3 - PostgreSQL Features, Security Scanner & Lint Rules (#176)
* feat: Parser enhancements batch 3 - Security scanner, lint rules & RETURNING clause This PR adds comprehensive SQL linting rules, integrates the security scanner into the CLI analyzer, and adds RETURNING clause support for DML statements. ## Security Scanner Integration (#154) - Integrated `pkg/sql/security` scanner into CLI's `SQLAnalyzer` - Now detects SQL injection patterns (tautologies, UNION-based, time-based) - Added `convertSecurityFindings()` to map security findings to analysis issues - Security score adjustments based on finding severity ## Phase 1 Lint Rules Complete (#155) Added 7 new lint rules for comprehensive SQL style checking: ### Whitespace Rules - **L003**: Consecutive blank lines detection with auto-fix - **L004**: Indentation depth check (warns on excessive nesting) - **L010**: Redundant whitespace detection (multiple spaces) with auto-fix ### Style Rules - **L006**: SELECT column alignment checking - **L008**: Comma placement consistency (trailing vs leading) - **L009**: Table aliasing consistency detection ### Keyword Rules - **L007**: Keyword case consistency with auto-fix (upper/lowercase) ## RETURNING Clause Support (#159) - Added `TokenTypeReturning` (379) for RETURNING keyword - Parser now supports RETURNING clause for INSERT, UPDATE, DELETE - Added `parseReturningColumns()` for parsing return expressions - Supports: column names, *, qualified names, expressions ## Additional Improvements - Added ALTER TABLE operation keywords (ADD, COLUMN, CONSTRAINT, RENAME, TO) - Extended SQL formatter with `AlterStatement` support - Comprehensive battle tests for all lint rules (50+ test cases) - Fixed L004 bug: depth > 9 now displays correctly in messages ## Test Results - All tests pass with race detection enabled - golangci-lint: 0 issues - 78+ lint-related tests covering edge cases 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> * fix: resolve GitHub Actions cache conflict with Go toolchain The Go 1.24 CI jobs were failing because: 1. setup-go installs Go 1.24 2. Go 1.24 sees `toolchain go1.25.0` in go.mod and auto-downloads it 3. setup-go then tries to restore cache with the same toolchain files 4. Cache extraction fails with "Cannot open: File exists" errors Fix by setting GOTOOLCHAIN=local to prevent auto-download, and fail-fast: false to run all matrix combinations even if one fails. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> * fix: resolve parser, tokenizer, and CLI issues (#165-#170) - Add CAST keyword to tokenizer keywordTokenTypes map (#167) - Fix || operator test with correct TokenTypeSingleQuotedString (#168) - Add SetOperation support to SQL formatter for UNION/EXCEPT/INTERSECT - Expand security scanner with UNION injection and stacked query detection (#170) - Add comprehensive linter test coverage (489 tests) (#165) - Verify recursive CTE parsing with UNION/UNION ALL (#166) - Verify MERGE CLI validation (#169) All 6 issues verified and closed: - #165: Linter test coverage - 489 tests, 67-96% coverage - #166: Recursive CTE parsing - 24 tests passing - #167: CAST expressions - tokenizer fix applied - #168: || operator - test fix applied - #169: MERGE CLI - full validation working - #170: Security scanner - 100% detection rate 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> * feat: implement PostgreSQL DISTINCT ON, FILTER clause & MERGE formatter Parser Enhancements: - Add PostgreSQL DISTINCT ON clause support with multi-column expressions - Implement SQL:2003 FILTER clause for aggregate functions - Add comprehensive test coverage (8 DISTINCT ON tests, 13 FILTER tests) CLI Formatter: - Add MERGE statement formatter with full clause support - Handle WHEN MATCHED/NOT MATCHED with UPDATE/INSERT/DELETE actions - Add 18 test cases for MERGE formatting scenarios Changes: - pkg/sql/ast/ast.go: Add DistinctOnColumns field to SelectStatement - pkg/sql/parser/select.go: Parse DISTINCT ON (expr, ...) syntax - pkg/sql/parser/window.go: Parse FILTER (WHERE condition) after aggregates - cmd/gosqlx/cmd/sql_formatter.go: Format MERGE statements - pkg/sql/keywords/keywords.go: Add FILTER keyword recognition New Test Files: - pkg/sql/parser/distinct_on_test.go (8 tests) - pkg/sql/parser/filter_clause_test.go (13 tests) - cmd/gosqlx/cmd/merge_formatter_test.go (18 tests) - examples/distinct_on_example.go (usage example) Related GitHub Issues: #171-#175 (PostgreSQL feature roadmap) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> * fix: address review comments - lint errors and improved error context Lint Fixes: - Remove redundant nil checks in filter_clause_test.go (staticcheck S1009) - len() for nil slices is defined as zero, so nil check is unnecessary Error Context Improvements (per review suggestion): - Use p.currentLocation() instead of empty Location{Line: 0, Column: 0} - Include p.currentToken.Literal for better debugging context - Applied to BETWEEN, LIKE, and IN subquery error messages 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> --------- Co-authored-by: Ajit Pratap Singh <[email protected]> Co-authored-by: Claude Opus 4.5 <[email protected]>
1 parent 58da53f commit 3d871ee

26 files changed

+4947
-76
lines changed

cmd/gosqlx/cmd/input_utils.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ func DetectAndReadInput(input string) (*InputResult, error) {
4040
input = strings.TrimSpace(input)
4141

4242
// Check if input looks like a file path using os.Stat
43-
if _, err := os.Stat(input); err == nil {
43+
_, statErr := os.Stat(input)
44+
if statErr == nil {
4445
// Input is a valid file path - perform comprehensive security validation
4546
if err := validate.ValidateInputFile(input); err != nil {
4647
return nil, fmt.Errorf("security validation failed: %w", err)
@@ -64,7 +65,14 @@ func DetectAndReadInput(input string) (*InputResult, error) {
6465
}, nil
6566
}
6667

67-
// Input is not a valid file path, treat as direct SQL
68+
// If stat failed, check if it looks like a file path that doesn't exist
69+
// (contains path separators or has .sql extension)
70+
if strings.Contains(input, string(filepath.Separator)) || strings.HasSuffix(strings.ToLower(input), ".sql") {
71+
// Looks like a file path but doesn't exist - return the original stat error
72+
return nil, fmt.Errorf("invalid file path: %w", statErr)
73+
}
74+
75+
// Input is not a file path, treat as direct SQL
6876
// Validate that it looks like SQL (basic heuristics)
6977
if !looksLikeSQL(input) {
7078
return nil, fmt.Errorf("input does not appear to be valid SQL or a file path: %s", input)
@@ -100,7 +108,7 @@ func looksLikeSQL(input string) bool {
100108
// Check for common SQL keywords at the beginning
101109
sqlKeywords := []string{
102110
"SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", "DROP", "ALTER",
103-
"WITH", "EXPLAIN", "ANALYZE", "SHOW", "DESCRIBE", "DESC",
111+
"WITH", "EXPLAIN", "ANALYZE", "SHOW", "DESCRIBE", "DESC", "MERGE",
104112
}
105113

106114
for _, keyword := range sqlKeywords {

0 commit comments

Comments
 (0)