Skip to content

Commit bac9275

Browse files
committed
more comprehensive rules based on crdb support
1 parent 43c7e8c commit bac9275

File tree

4 files changed

+167
-7
lines changed

4 files changed

+167
-7
lines changed
Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
# postgres_to_crdb.yaml — Comprehensive CRDB Compatibility Rules based on https://www.cockroachlabs.com/docs/v25.2/sql-feature-support
2+
13
- id: malformed_dml_statements
24
match: '^(SELECT|INSERT|UPDATE|DELETE FROM)\s*$'
35
message: "Possibly malformed or incomplete SQL statement"
46
level: warning
57
tags: [syntax]
68

79
- id: special_char_in_identifier
8-
match: '"[^"]*#\w*"'
10+
match: '"[^\"]*#\w*"'
911
message: "Table name contains unsupported special character (#)"
1012
level: error
1113
tags: [table, identifier]
@@ -16,8 +18,62 @@
1618
level: error
1719
tags: [function]
1820

19-
#- id: low_token_sql
20-
#match: '^(\S+\s*){1,2}$'
21-
#message: "Extremely short SQL likely malformed"
22-
#level: warning
23-
#tags: [syntax]
21+
- id: with_cte
22+
match: '^\s*WITH\s+'
23+
message: "CTE (WITH clause) detected"
24+
level: warning
25+
tags: [cte, syntax]
26+
27+
- id: upsert_syntax
28+
match: '^\s*UPSERT\s+'
29+
message: "UPSERT syntax (CockroachDB supports but should be reviewed)"
30+
level: info
31+
tags: [upsert, insert]
32+
33+
- id: json_ops
34+
match: '->|->>|::json[b]?' # Look for JSON navigation or cast
35+
message: "JSON/JSONB usage detected"
36+
level: info
37+
tags: [json]
38+
39+
- id: row_values
40+
match: '\(.*\).*IN\s*\(' # e.g., WHERE (a, b) IN ((1, 2))
41+
message: "ROW VALUES in IN clause"
42+
level: warning
43+
tags: [rowvalues, comparison]
44+
45+
- id: window_function
46+
match: '\bOVER\s*\('
47+
message: "Window function usage (e.g., RANK, ROW_NUMBER)"
48+
level: info
49+
tags: [window, analytics]
50+
51+
- id: set_ops
52+
match: '\s+(UNION|INTERSECT|EXCEPT)\s+'
53+
message: "Set operation (UNION, INTERSECT, EXCEPT)"
54+
level: info
55+
tags: [setops]
56+
57+
- id: case_expr
58+
match: '\bCASE\b.*\bWHEN\b.*\bTHEN\b'
59+
message: "CASE expression detected"
60+
level: info
61+
tags: [case, conditional]
62+
63+
- id: time_interval
64+
match: 'INTERVAL\s+[''\"]'
65+
message: "TIME INTERVAL expression"
66+
level: info
67+
tags: [interval, time]
68+
69+
- id: group_by_rollup
70+
match: 'GROUP BY ROLLUP\('
71+
message: "ROLLUP clause used"
72+
level: warning
73+
tags: [aggregation, rollup]
74+
75+
- id: filter_clause
76+
match: 'FILTER\s*\(\s*WHERE'
77+
message: "FILTER clause used in aggregation"
78+
level: warning
79+
tags: [aggregation, filter]

crdb_sql_audit/rules_engine.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ def apply_rules(sql, rules):
3333
logging.info(f"✅ MATCH: Rule {rule['id']} matched on SQL: {sql}")
3434

3535
# Try to extract SQL type (optional fallback)
36-
stmt_type_match = re.match(r'^\s*(SELECT|INSERT|UPDATE|DELETE|BEGIN|COMMIT|ROLLBACK|SAVEPOINT)', sql, re.IGNORECASE)
36+
stmt_type_match = re.match(
37+
r'^\s*(SELECT|INSERT|UPDATE|DELETE|UPSERT|WITH|BEGIN|COMMIT|ROLLBACK|SAVEPOINT|MERGE|CALL)',
38+
sql,
39+
re.IGNORECASE
40+
)
3741
sql_type = stmt_type_match.group(1).upper() if stmt_type_match else rule.get("type", "OTHER")
3842

3943
matched.append({

rules/mysql_to_crdb.yaml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
- id: mysql_limit_offset
2+
match: 'LIMIT\s+\d+\s*,\s*\d+'
3+
message: "MySQL LIMIT offset, count is not supported; use LIMIT ... OFFSET"
4+
level: warning
5+
tags: [mysql, pagination]
6+
7+
- id: mysql_if_func
8+
match: '\bIF\s*\('
9+
message: "MySQL IF(...) must be replaced with CASE"
10+
level: warning
11+
tags: [mysql, conditional]
12+
13+
- id: mysql_backticks
14+
match: '`[^`]+`'
15+
message: "Backtick-quoted identifiers should use double quotes"
16+
level: warning
17+
tags: [mysql, identifier]
18+
19+
- id: mysql_unsigned
20+
match: '\bUNSIGNED\b'
21+
message: "UNSIGNED types not supported in CockroachDB"
22+
level: error
23+
tags: [mysql, types]
24+
25+
- id: mysql_enum
26+
match: '\bENUM\s*\('
27+
message: "ENUM should be rewritten as CHECK constraints"
28+
level: warning
29+
tags: [mysql, types]
30+
31+
- id: mysql_now
32+
match: '\bNOW\s*\(\)'
33+
message: "NOW() is supported but may behave differently — use with care"
34+
level: info
35+
tags: [mysql, datetime]
36+
37+
- id: mysql_auto_increment
38+
match: '\bAUTO_INCREMENT\b'
39+
message: "Use SERIAL or GENERATED AS IDENTITY instead of AUTO_INCREMENT"
40+
level: error
41+
tags: [mysql, identity]
42+
43+
- id: mysql_text_blob
44+
match: '\b(TEXT|BLOB)\b'
45+
message: "TEXT and BLOB types must be mapped to STRING/BYTES"
46+
level: warning
47+
tags: [mysql, types]
48+
49+
- id: mysql_regexp
50+
match: '\bREGEXP\b'
51+
message: "REGEXP should be rewritten using SIMILAR TO or ~ operator"
52+
level: warning
53+
tags: [mysql, expressions]

rules/oracle_to_crdb.yaml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
- id: oracle_merge
2+
match: '^\s*MERGE\s+INTO'
3+
message: "Oracle-style MERGE statements are not supported in CockroachDB"
4+
level: error
5+
tags: [oracle, merge]
6+
7+
- id: oracle_dual_table
8+
match: '\s+FROM\s+DUAL\b'
9+
message: "Oracle's DUAL table should be removed or rewritten"
10+
level: warning
11+
tags: [oracle, dual]
12+
13+
- id: oracle_rownum
14+
match: '\bROWNUM\b'
15+
message: "ROWNUM is not supported; use LIMIT instead"
16+
level: error
17+
tags: [oracle, pagination]
18+
19+
- id: oracle_decode
20+
match: '\bDECODE\s*\('
21+
message: "DECODE not supported; use CASE instead"
22+
level: warning
23+
tags: [oracle, conditional]
24+
25+
- id: oracle_nvl
26+
match: '\bNVL\s*\('
27+
message: "NVL should be replaced with COALESCE"
28+
level: info
29+
tags: [oracle, null-handling]
30+
31+
- id: oracle_number_precision
32+
match: '\bNUMBER\s*(\(\d+\)|\(\d+,\d+\))?'
33+
message: "NUMBER types should be mapped explicitly to INT, DECIMAL, etc."
34+
level: warning
35+
tags: [oracle, types]
36+
37+
- id: oracle_sysdate
38+
match: '\bSYSDATE\b'
39+
message: "SYSDATE should be replaced with CURRENT_TIMESTAMP"
40+
level: warning
41+
tags: [oracle, datetime]
42+
43+
- id: oracle_plsql_block
44+
match: '^\s*BEGIN\s+.+END\s*;'
45+
message: "PL/SQL block detected — CockroachDB does not support procedural code"
46+
level: error
47+
tags: [oracle, plsql]

0 commit comments

Comments
 (0)