FuzzParse fuzzes the full parse pipeline (tokenizer + token conversion + parser) with arbitrary SQL input. The parser must never panic - only return errors gracefully.
(f *testing.F)
| 26 | // FuzzParse fuzzes the full parse pipeline (tokenizer + token conversion + parser) |
| 27 | // with arbitrary SQL input. The parser must never panic - only return errors gracefully. |
| 28 | func FuzzParse(f *testing.F) { |
| 29 | // Seed from existing test fixture files |
| 30 | seedDirs := []string{ |
| 31 | "testdata/real_world", |
| 32 | "testdata/postgresql", |
| 33 | "testdata/mysql", |
| 34 | } |
| 35 | for _, dir := range seedDirs { |
| 36 | files, err := filepath.Glob(filepath.Join(dir, "*.sql")) |
| 37 | if err != nil { |
| 38 | continue |
| 39 | } |
| 40 | for _, file := range files { |
| 41 | data, err := os.ReadFile(file) |
| 42 | if err != nil { |
| 43 | continue |
| 44 | } |
| 45 | for _, stmt := range strings.Split(string(data), ";") { |
| 46 | stmt = strings.TrimSpace(stmt) |
| 47 | if stmt != "" && !strings.HasPrefix(stmt, "--") { |
| 48 | f.Add(stmt) |
| 49 | } |
| 50 | } |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | // Hand-crafted seeds covering edge cases |
| 55 | seeds := []string{ |
| 56 | "SELECT 1", |
| 57 | "SELECT * FROM t", |
| 58 | "INSERT INTO t (a) VALUES (1)", |
| 59 | "UPDATE t SET a = 1 WHERE b = 2", |
| 60 | "DELETE FROM t WHERE a = 1", |
| 61 | "CREATE TABLE t (id INT PRIMARY KEY)", |
| 62 | "DROP TABLE t", |
| 63 | "SELECT a FROM t1 JOIN t2 ON t1.id = t2.id", |
| 64 | "SELECT * FROM t WHERE a IN (1, 2, 3)", |
| 65 | "SELECT * FROM t WHERE a BETWEEN 1 AND 10", |
| 66 | "SELECT COUNT(*) FROM t GROUP BY a HAVING COUNT(*) > 1", |
| 67 | "WITH cte AS (SELECT 1) SELECT * FROM cte", |
| 68 | "SELECT * FROM t ORDER BY a NULLS FIRST", |
| 69 | "SELECT ROW_NUMBER() OVER (PARTITION BY a ORDER BY b) FROM t", |
| 70 | "MERGE INTO t USING s ON t.id = s.id WHEN MATCHED THEN UPDATE SET t.a = s.a", |
| 71 | "SELECT data->>'name' FROM t", |
| 72 | "TRUNCATE TABLE t CASCADE", |
| 73 | "", |
| 74 | ";;;", |
| 75 | "SELECT", |
| 76 | "FROM", |
| 77 | "WHERE AND OR", |
| 78 | "SELECT 'unclosed string", |
| 79 | "SELECT (((", |
| 80 | "SELECT * FROM", |
| 81 | "INSERT INTO", |
| 82 | "SELECT 1 UNION ALL SELECT 2 INTERSECT SELECT 3", |
| 83 | "SELECT CASE WHEN 1=1 THEN 'a' ELSE 'b' END FROM t", |
| 84 | "SELECT CAST(1 AS VARCHAR) FROM t", |
| 85 | } |
nothing calls this directly
no test coverage detected