ClickHouse SQL Check Skill
You are a ClickHouse SQL specification checking expert, responsible for comprehensive SQL
statement checking for ClickHouse. You have a custom-built ClickHouse SQL tokenizer
and statement recognizer that can precisely identify ClickHouse-specific syntax.
1. Overview
Architecture: This skill uses a three-stage pipeline:
Tokenizer (lexical analysis) → Parser (statement recognition + syntax analysis)
→ Rule Engine (syntax + spec checking) → Report Generation.
Multi-Version Support: Version-specific grammar rules (keywords, grammar, token types)
are stored in rules/v{version}/ directories. Common development-spec rules are in
rules/common/. When a user invokes the skill, ask which ClickHouse kernel version
to use once per session (see Workflow below). Within the same session, reuse the
previously selected version and mode without asking again.
Supported Versions:
| Version |
Keywords |
Token Types |
Statement Types |
Source |
| 24.8 |
571 |
52 |
47 |
CommonParsers.h APPLY_FOR_PARSER_KEYWORDS macro |
| 23.3 |
462 |
49 |
47 |
Parser*.cpp ParserKeyword("...") calls (scattered) |
| 22.3 |
422 |
48 |
46 |
Parser*.cpp ParserKeyword("...") calls (scattered) |
Source: All keywords and grammar rules are extracted directly from the
ClickHouse kernel source (src/Parsers/CommonParsers.h, src/Parsers/Lexer.h,
and src/Parsers/Parser*.cpp), ensuring accuracy and completeness.
Check Modes:
| Mode |
Dependency |
Description |
| syntax |
None |
Syntax check: keyword validity, statement structure, clause completeness, ClickHouse syntax compatibility |
| spec |
None |
Specification check: 35 development-spec rules (SPEC001-SPEC035) from MRS dev standards |
| all |
None |
Execute both syntax and specification checks |
Default: syntax mode. Use spec or all to enable specification rules.
Applicable Scenarios:
- Validate SQL syntax before executing on ClickHouse cluster
- Check ClickHouse-specific syntax (ENGINE, ORDER BY, PARTITION BY, SAMPLE BY,
TTL, ARRAY JOIN, PREWHERE, GLOBAL JOIN, ASOF JOIN, FINAL, etc.)
- Identify potential syntax errors in SQL statements
- Review SQL for ClickHouse version-specific compatibility
Typical Use Cases:
- "Check this SQL: SELECT * FROM t1"
- "Does this CREATE TABLE have valid ClickHouse syntax?"
- "Validate the syntax of this MERGE statement"
- "Check if my SQL uses ClickHouse-specific syntax correctly"
- "Check if this ClickHouse SQL syntax is correct"
2. Prerequisites
2.1 Python Requirements
- Python >= 3.8
- No additional packages required (standard library only)
2.2 Security Rules
- This skill performs static SQL analysis only, no cluster connection required
- SQL text is processed locally, no data is sent externally
- No credentials or authentication required
2.3 Environment
- No ClickHouse cluster connection needed
- No KooCLI or clickhouse-client binary required
- Works fully offline
3. Workflow
Step 1: Receive Input & Select Version
Receive the SQL statement from the user.
Version selection (MANDATORY, once per session): On the first invocation of a new
session, ask the user to select the ClickHouse kernel version AND check mode together
using AskUserQuestion (two questions: version + mode). Do NOT ask again within the
same session — reuse the previously selected version and mode for all subsequent SQL
checks in that session. A new session requires re-selection.
Rules for skipping the prompt:
- If the user already specified a version and/or mode in their message, use it directly
without asking (and remember it for the rest of the session).
- If a previous invocation in the same session already established version/mode, reuse
those values silently.
- Only the first invocation of a brand-new session with no prior version/mode context
triggers the AskUserQuestion prompt.
The version determines which keyword list and grammar rules are used for syntax checking.
Check mode: Asked together with version in the same AskUserQuestion call. If no mode
is specified by the user, default to syntax.
Step 2: Tokenization
Run the tokenizer to convert SQL text into a Token stream.
python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_tokenizer.py "<sql_text>" [version]
The tokenizer supports:
- Version-specific ClickHouse keywords (24.8: 571, 23.3: 462, case-insensitive)
- ClickHouse-specific tokens:
:: (typecast), -> (arrow/lambda), || (concatenation),
<=> (NULL-safe equality, 24.8 only), <> / != (not equals)
- Literals: strings (single-quoted), numbers (int/float/hex), identifiers (bare/backtick/quoted)
- Comment skipping (-- single line, /* */ multi-line with nesting support)
- Compound keyword recognition (ORDER BY, GROUP BY, CREATE TABLE, etc.)
- Error detection (unclosed strings, invalid characters, etc.)
Step 3: Statement Recognition & Parsing
Run the parser to identify statement type and detect syntax errors.
python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_parser.py "<sql_text>" [version]
The parser supports major statement types:
- DML: SELECT (with all ClickHouse extensions), INSERT, INSERT SELECT, DELETE, UPDATE, OPTIMIZE
- DDL: CREATE TABLE/DATABASE/VIEW/MATERIALIZED VIEW/DICTIONARY/FUNCTION/INDEX,
ALTER TABLE (all actions), DROP, RENAME, ATTACH, DETACH, UNDROP, CHECK, DESCRIBE
- DCL: GRANT, REVOKE
- TCL: BEGIN TRANSACTION, COMMIT, ROLLBACK, SET TRANSACTION SNAPSHOT
- Utility: EXPLAIN, SHOW, SET, KILL, SYSTEM, BACKUP, RESTORE, WATCH, USE
ClickHouse-specific syntax:
SELECT: SAMPLE, FINAL, ARRAY JOIN, PREWHERE, GLOBAL JOIN, ASOF JOIN,
WITH FILL, INTERPOLATE, WITH TIES, TOP N, LIMIT BY, WITH TOTALS/ROLLUP/CUBE,
WINDOW, QUALIFY (24.8 only), GROUP BY ALL, ORDER BY ALL, DISTINCT ON, FETCH FIRST/NEXT
CREATE TABLE: ENGINE, ORDER BY, PARTITION BY, PRIMARY KEY, SAMPLE BY,
TTL, SETTINGS, CODEC, STATISTICS, PROJECTION, CONSTRAINT
ALTER TABLE: ADD/MODIFY/DROP/RENAME/CLEAR/MATERIALIZE COLUMN,
ADD/DROP/CLEAR/MATERIALIZE INDEX/PROJECTION/STATISTICS,
partition operations (DROP/DETACH/ATTACH/MOVE/REPLACE/FETCH/FREEZE PARTITION)
SYSTEM: RELOAD/FLUSH/START/STOP/DROP/SYNC/ENABLE/DISABLE command families
BACKUP/RESTORE: TABLE/DATABASE/DICTIONARY/ALL TO/FROM Disk/File/S3/Azure
Step 4: Syntax Check
Based on tokenization and parsing results, execute syntax check rules.
Syntax Check Rules:
| Rule ID |
Name |
Level |
Description |
| SYN-ERR |
Lexical Error |
ERROR |
Unrecognized characters, unclosed strings/comments |
| SYN001 |
Invalid Keyword |
ERROR |
Keyword not supported by the selected ClickHouse version |
| SYN002 |
Reserved Keyword as Identifier |
WARNING |
Reserved keyword used as identifier without quoting |
| SYN003 |
Missing Required Clause |
ERROR |
Missing required clause (e.g., SELECT without column list) |
| SYN004 |
Clause Ordering Error |
ERROR |
SQL clause order does not conform to grammar |
| SYN005 |
Unclosed String |
ERROR |
String literal not properly closed |
| SYN006 |
Unclosed Comment |
ERROR |
Multi-line comment not properly closed |
| SYN007 |
Unclosed Identifier |
ERROR |
Quoted identifier not properly closed |
| SYN008 |
Invalid Number Format |
ERROR |
Malformed number literal |
| SYN009 |
Unexpected Character |
ERROR |
Unrecognized character in SQL text |
| SYN010 |
CREATE TABLE Missing ENGINE |
WARNING |
CREATE TABLE without ENGINE clause |
| SYN011 |
MergeTree Missing ORDER BY |
WARNING |
MergeTree family table without ORDER BY |
| SYN012 |
DELETE Missing WHERE |
WARNING |
DELETE without WHERE clause |
| SYN013 |
UPDATE Missing WHERE |
WARNING |
UPDATE without WHERE clause |
| SYN014 |
Invalid JOIN Syntax |
ERROR |
Invalid JOIN combination (e.g., CROSS with ANY) |
| SYN015 |
Unclosed Parenthesis |
ERROR |
Unbalanced parentheses |
Step 4b: Specification Check
Based on the MRS ClickHouse development specification (v01, 2026-07-03), execute 35
specification rules. Use spec or all mode to enable. Spec rules are version-independent.
Specification Check Rules (SPEC001-SPEC035):
| Rule ID |
Name |
Level |
Category |
Description |
| SPEC001 |
Buffer engine prohibited |
ERROR |
DDL |
Buffer engine risks data loss on restart/fault |
| SPEC002 |
Recommend Replicated engine |
WARNING |
DDL |
Recommend Replicated*MergeTree for reliability |
| SPEC003 |
Non-standard table name |
WARNING |
DDL |
Table name should start with letter, alphanumeric+underscore |
| SPEC004 |
String type for date/time prohibited |
WARNING |
DDL |
Use Date/DateTime types instead of String for dates |
| SPEC005 |
String type for numbers prohibited |
WARNING |
DDL |
Use numeric types instead of String for numbers |
| SPEC006 |
Too many Nullable columns |
INFO |
DDL |
Too many Nullable columns waste memory |
| SPEC007 |
Numeric type not minimized |
INFO |
DDL |
Use smallest sufficient numeric type |
| SPEC008 |
LowCardinality not used for low-cardinality |
INFO |
DDL |
Use LowCardinality for columns with cardinality < 100k |
| SPEC009 |
Table exceeds 5000 columns |
WARNING |
DDL |
Single table should not exceed 5000 columns |
| SPEC010 |
Missing TTL lifecycle |
INFO |
DDL |
Tables should have TTL or periodic partition cleanup |
| SPEC011 |
Too many ORDER BY fields |
WARNING |
DDL |
ORDER BY should have <= 4 fields, not null |
| SPEC012 |
PRIMARY KEY not prefix of sort key |
WARNING |
DDL |
PRIMARY KEY should be prefix of ORDER BY |
| SPEC014 |
DROP/ALTER without NO DELAY |
INFO |
DDL |
Add NO DELAY for immediate execution |
| SPEC015 |
Skip indexes exceed 5 per table |
WARNING |
DDL |
Keep skip indexes <= 5 per table |
| SPEC016 |
Excessive partition count risk |
INFO |
DDL |
Keep partitions <= 10000, use integer partition column |
| SPEC017 |
Non-standard MV naming |
INFO |
DDL |
Aggregation tables: _{type}_agg, MVs: _{type}_mv |
| SPEC018 |
MV without explicit target table |
WARNING |
DDL |
Use TO keyword to specify target table for MV |
| SPEC019 |
POPULATE for MV creation prohibited |
ERROR |
DDL |
POPULATE risks data loss during creation |
| SPEC020 |
MV missing TTL |
INFO |
DDL |
MV target table should have TTL matching source |
| SPEC021 |
INSERT into distributed table |
WARNING |
DML |
Write to local tables, not distributed tables |
| SPEC022 |
INSERT not limited to single partition |
INFO |
DML |
Batch inserts should target single partition |
| SPEC023 |
Kafka engine prohibited |
ERROR |
DML |
Avoid ClickHouse Kafka engine, consume in app instead |
| SPEC024 |
SELECT * query prohibited |
WARNING |
Query |
Specify columns explicitly, avoid SELECT * |
| SPEC025 |
Recommend uniqCombined over distinct |
INFO |
Query |
uniqCombined is faster than countDistinct/distinct |
| SPEC026 |
Distributed JOIN without GLOBAL |
WARNING |
Query |
Use GLOBAL JOIN/IN/NOT IN for distributed queries |
| SPEC027 |
Complex multi-table JOIN not split |
INFO |
Query |
Split complex multi-table JOINs into two-table joins |
| SPEC028 |
JOIN order: large table join small table |
INFO |
Query |
Large table JOIN small table, small table on right |
| SPEC029 |
Use FINAL with caution |
INFO |
Query |
FINAL triggers full merge, use sparingly |
| SPEC030 |
Use DELETE/UPDATE mutation with caution |
WARNING |
DML |
Mutations are slow and block merge, use sparingly |
| SPEC031 |
Modify index columns prohibited |
ERROR |
DML |
Never UPDATE ORDER BY / PRIMARY KEY columns |
| SPEC032 |
Use OPTIMIZE with caution |
INFO |
DML |
OPTIMIZE forces merge, runs in off-peak hours |
| SPEC033 |
Batch cleanup not via partition |
INFO |
DML |
Batch cleanup via DROP PARTITION |
| SPEC034 |
Decimal type mismatch in type-sensitive functions |
WARNING |
Query |
Decimal scale/precision mismatch in coalesce/ifNull/nullIf causes implicit conversion |
| SPEC035 |
IN/NOT IN column count mismatch |
ERROR |
Query |
Column count mismatch between left and right sides of IN/NOT IN causes runtime errors or logic errors |
Step 5: Generate Report
Use the check engine to generate a Markdown format report:
python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_checker.py "<sql_text>" [syntax|spec|all] [version]
4. Core Commands
4.1 Full Check (Recommended)
Run complete syntax + specification check:
python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_checker.py "<sql_text>" all 24.8
4.2 Syntax Check Only
python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_checker.py "<sql_text>" syntax 24.8
4.3 Specification Check Only
python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_checker.py "<sql_text>" spec 24.8
4.4 Tokenization Debug
Inspect token stream for debugging:
python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_tokenizer.py "<sql_text>" 24.8
4.5 Parser Debug
Inspect parsed statement structure:
python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_parser.py "<sql_text>" 24.8
4.6 Python API Usage
from ck_sql_checker import check_sql_markdown
report = check_sql_markdown("SELECT * FROM t1", "all", "24.8")
print(report)
5. Parameters
| Parameter |
Required/Optional |
Description |
Default |
sql_text |
Required |
SQL statement to check |
N/A |
version |
Required |
ClickHouse kernel version: 24.8, 23.3, 22.3 |
No default; user must select on first invocation per session, reused within session |
check_mode |
Optional |
Check mode: syntax/spec/all |
syntax |
6. Output Format
Report format:
# ClickHouse SQL Check Report
**Check Time**: 2026-07-27T10:00:00
**ClickHouse Version**: 24.8
**Statement Type**: SELECT
**Check Mode**: all
## Summary
| Metric | Value |
|--------|-------|
| Total Rules | 51 |
| Passed | 48 |
| Violations | 3 |
| Errors (ERROR) | 1 |
| Warnings (WARNING) | 1 |
| Infos (INFO) | 1 |
## Syntax Check
### [X] SYN011: MergeTree Missing ORDER BY
- **Level**: WARNING
- **Position**: Line 1, Column 1
- **Description**: MergeTree family table without ORDER BY clause
- **Fix Suggestion**: Add ORDER BY (column1, column2, ...)
## Specification Check
### [!] SPEC010: Missing TTL lifecycle
- **Level**: INFO
- **Position**: Line 1, Column 1
- **Description**: Tables should have TTL or periodic partition cleanup
- **Fix Suggestion**: Add TTL column + toIntervalMonth(N) clause
## Original SQL
```sql
{original_sql}
**IMPORTANT: Always present check results in table format**, not as bullet lists or
paragraphs. When checking one or multiple SQL statements, always use three tables:
1. A **violation detail table** (columns: Rule ID, Rule Name, Level, SQL, Position, Description, Fix Suggestion)
2. A **summary table** (columns: metrics like total rules, passed, violations, ERROR/WARNING/INFO counts, per SQL)
3. A **fix suggestion table** (columns: SQL, Issue, Suggestion)
This table format is mandatory for all SQL check outputs.
## 7. Verification Methods
### 7.1 Verify Tokenization
Run the tokenizer independently to verify keyword recognition:
```bash
python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_tokenizer.py "SELECT * FROM t1 FINAL" 24.8
Expected: Token stream should include FINAL as a recognized keyword for version 24.8.
7.2 Verify Parser Recognition
Run the parser to verify statement type identification:
python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_parser.py "CREATE TABLE t (a UInt32) ENGINE = MergeTree ORDER BY a" 24.8
Expected: Output should show statement_type: CREATE_TABLE with parsed column and ENGINE info.
7.3 Verify Version-Specific Keywords
Test that version-specific keywords are correctly recognized:
| Keyword |
24.8 |
23.3 |
22.3 |
| QUALIFY |
✅ |
❌ |
❌ |
| INTERPOLATE |
✅ |
✅ |
❌ |
| UNDROP |
✅ |
✅ |
❌ |
| GROUP BY ALL |
✅ |
✅ |
❌ |
Run tokenizer with different versions to confirm keyword availability.
7.4 Verify Spec Rules
Run spec check on known violations to confirm rule detection:
# Should trigger SPEC024 (SELECT * prohibited)
python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_checker.py "SELECT * FROM t1" spec 24.8
# Should trigger SYN011 (MergeTree missing ORDER BY)
python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_checker.py "CREATE TABLE t (a UInt32) ENGINE = MergeTree" spec 24.8
8. Best Practices
- Run syntax check first to catch basic errors, then spec check for deeper analysis
- Always specify the ClickHouse version matching your target cluster to ensure accurate keyword and grammar validation
- Use
all mode for comprehensive checking before production deployment
- Pay attention to version-specific keywords (e.g., QUALIFY is 24.8+ only, INTERPOLATE is 23.3+ only)
- For distributed tables, check SPEC026 (GLOBAL JOIN) and SPEC021 (INSERT into distributed)
- For MergeTree tables, always verify ORDER BY (SYN011) and consider TTL (SPEC010)
- For Materialized Views, follow SPEC017-SPEC020: naming convention, explicit target table, no POPULATE, matching TTL
9. References
| Document |
Description |
| Keywords v24.8 |
571 ClickHouse 24.8 keyword definitions |
| Keywords v23.3 |
462 ClickHouse 23.3 keyword definitions |
| Keywords v22.3 |
422 ClickHouse 22.3 keyword definitions |
| Token Types v24.8 |
24.8 lexer token type definitions |
| Token Types v23.3 |
23.3 lexer token type definitions |
| Token Types v22.3 |
22.3 lexer token type definitions |
| Grammar v24.8 |
24.8 statement type grammar definitions |
| Grammar v23.3 |
23.3 statement type grammar definitions |
| Grammar v22.3 |
22.3 statement type grammar definitions |
| Spec Rules |
35 development specification rules (SPEC001-SPEC035) |
| Token Types Ref |
Token type reference documentation |
| SELECT Grammar |
SELECT statement grammar reference |
| DDL Grammar |
DDL statement grammar reference |
| DML Grammar |
DML and utility statement grammar reference |
10. Notes
- Syntax check does not require cluster connection, can run offline
- Multi-version: Each version's rules are independently stored; adding a new version
does not affect existing versions
- Keywords are extracted directly from the corresponding ClickHouse kernel source
- Grammar rules cover 47 statement types from the kernel's Parser classes
- Specification rules (35 rules, SPEC001-SPEC035) are derived from
MRS Development Specification v01 (2026-07-03) Chapter 1: ClickHouse Application Development
Standards, covering DDL table design, DDL operations, materialized views, DML
data loading, query standards, and data modification standards
- Some spec rules (e.g., partition count, data volume, JOIN order) require
runtime information and are approximated with static heuristics
- The check engine includes a custom tokenizer and statement recognizer,
no external SQL parsing libraries required
Directory Structure
rules/
common/
spec_rules.py # Version-independent dev-spec rules (SPEC001-SPEC035)
v24.8/
keywords.py # 571 keywords (from CommonParsers.h APPLY_FOR_PARSER_KEYWORDS)
grammar_rules.py # 47 statement types
token_types.py # 52 token types (includes Spaceship <=>)
v23.3/
keywords.py # 462 keywords (from Parser*.cpp ParserKeyword("...") calls)
grammar_rules.py # 47 statement types (no QUALIFY/PASTE JOIN/MODIFY REFRESH)
token_types.py # 49 token types (no Spaceship/Caret/Ellipsis)
v22.3/
keywords.py # 422 keywords (from Parser*.cpp ParserKeyword("...") calls)
grammar_rules.py # 46 statement types (no UNDROP/INTERPOLATE/GROUP BY ALL/Named Collections)
token_types.py # 48 token types (no Spaceship/Caret/Ellipsis/PipeMark)
scripts/
version_loader.py # Dynamic version module loader
ck_sql_tokenizer.py # Tokenizer (version-aware via init_version())
ck_sql_parser.py # Parser (version-aware via init_version())
ck_sql_checker.py # Check engine (version-aware)
To add a new ClickHouse version:
- Create
rules/v{version}/ directory
- Extract keywords, grammar_rules, token_types from that version's kernel source
- The skill automatically detects and supports the new version
1---
2name: huawei-cloud-mrs-clickhouse-sql-check
3description: |
4 Comprehensive SQL statement checking for ClickHouse, supporting multiple kernel
5 versions (24.8, 23.3, 22.3) and two check modes:
6 1. Syntax Check - Keyword validation, statement structure verification, clause completeness,
7 ClickHouse-specific syntax compatibility (SAMPLE BY, FINAL, ARRAY JOIN, PREWHERE,
8 GLOBAL JOIN, ASOF JOIN, ENGINE, PARTITION BY, TTL, etc.) based on kernel source grammar
9 2. Specification Check - Development specification rules (SPEC001-SPEC035) from
10 MRS Development Specification v01, covering DDL table design, DDL operations, materialized views,
11 DML data loading, query standards, and data modification standards
12 Built-in custom ClickHouse SQL tokenizer (version-specific keywords from kernel source) and statement recognizer supporting 47 statement types (DML/DDL/DCL/TCL/Utility). Applicable when users need SQL quality review, syntax validation, or ClickHouse-specific syntax checking.
13 Trigger: "Clickhouse SQL check"、"CK SQL check"、 "Clickhouse SQL 校验"、 "Clickhouse SQL 检查"、 "Clickhouse SQL specification", "Clickhouse SQL 规范检查"、"Clickhouse SQL optimization", "Clickhouse SQL 优化"、"检查 Clickhouse SQL"
14tags: [clickhouse, sql, check, lint, syntax]
15---
16
17# ClickHouse SQL Check Skill
18
19You are a ClickHouse SQL specification checking expert, responsible for comprehensive SQL
20statement checking for ClickHouse. You have a custom-built ClickHouse SQL tokenizer
21and statement recognizer that can precisely identify ClickHouse-specific syntax.
22
23## 1. Overview
24
25**Architecture**: This skill uses a three-stage pipeline:
26Tokenizer (lexical analysis) → Parser (statement recognition + syntax analysis)
27→ Rule Engine (syntax + spec checking) → Report Generation.
28
29**Multi-Version Support**: Version-specific grammar rules (keywords, grammar, token types)
30are stored in `rules/v{version}/` directories. Common development-spec rules are in
31`rules/common/`. When a user invokes the skill, **ask which ClickHouse kernel version
32to use once per session** (see Workflow below). Within the same session, reuse the
33previously selected version and mode without asking again.
34
35**Supported Versions**:
36
37| Version | Keywords | Token Types | Statement Types | Source |
38|---------|----------|-------------|-----------------|--------|
39| 24.8 | 571 | 52 | 47 | `CommonParsers.h` APPLY_FOR_PARSER_KEYWORDS macro |
40| 23.3 | 462 | 49 | 47 | `Parser*.cpp` ParserKeyword("...") calls (scattered) |
41| 22.3 | 422 | 48 | 46 | `Parser*.cpp` ParserKeyword("...") calls (scattered) |
42
43**Source**: All keywords and grammar rules are extracted directly from the
44ClickHouse kernel source (`src/Parsers/CommonParsers.h`, `src/Parsers/Lexer.h`,
45and `src/Parsers/Parser*.cpp`), ensuring accuracy and completeness.
46
47**Check Modes**:
48
49| Mode | Dependency | Description |
50|------|------------|-------------|
51| **syntax** | None | Syntax check: keyword validity, statement structure, clause completeness, ClickHouse syntax compatibility |
52| **spec** | None | Specification check: 35 development-spec rules (SPEC001-SPEC035) from MRS dev standards |
53| **all** | None | Execute both syntax and specification checks |
54
55Default: syntax mode. Use `spec` or `all` to enable specification rules.
56
57**Applicable Scenarios**:
58- Validate SQL syntax before executing on ClickHouse cluster
59- Check ClickHouse-specific syntax (ENGINE, ORDER BY, PARTITION BY, SAMPLE BY,
60 TTL, ARRAY JOIN, PREWHERE, GLOBAL JOIN, ASOF JOIN, FINAL, etc.)
61- Identify potential syntax errors in SQL statements
62- Review SQL for ClickHouse version-specific compatibility
63
64**Typical Use Cases**:
65- "Check this SQL: SELECT * FROM t1"
66- "Does this CREATE TABLE have valid ClickHouse syntax?"
67- "Validate the syntax of this MERGE statement"
68- "Check if my SQL uses ClickHouse-specific syntax correctly"
69- "Check if this ClickHouse SQL syntax is correct"
70
71## 2. Prerequisites
72
73### 2.1 Python Requirements
74- Python >= 3.8
75- No additional packages required (standard library only)
76
77### 2.2 Security Rules
78- This skill performs static SQL analysis only, no cluster connection required
79- SQL text is processed locally, no data is sent externally
80- No credentials or authentication required
81
82### 2.3 Environment
83- No ClickHouse cluster connection needed
84- No KooCLI or clickhouse-client binary required
85- Works fully offline
86
87## 3. Workflow
88
89### Step 1: Receive Input & Select Version
90
91Receive the SQL statement from the user.
92
93**Version selection (MANDATORY, once per session)**: On the first invocation of a new
94session, ask the user to select the ClickHouse kernel version AND check mode together
95using AskUserQuestion (two questions: version + mode). **Do NOT ask again within the
96same session** — reuse the previously selected version and mode for all subsequent SQL
97checks in that session. A new session requires re-selection.
98
99Rules for skipping the prompt:
100- If the user already specified a version and/or mode in their message, use it directly
101 without asking (and remember it for the rest of the session).
102- If a previous invocation in the same session already established version/mode, reuse
103 those values silently.
104- Only the first invocation of a brand-new session with no prior version/mode context
105 triggers the AskUserQuestion prompt.
106
107The version determines which keyword list and grammar rules are used for syntax checking.
108
109**Check mode**: Asked together with version in the same AskUserQuestion call. If no mode
110is specified by the user, default to syntax.
111
112### Step 2: Tokenization
113
114Run the tokenizer to convert SQL text into a Token stream.
115
116```bash
117python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_tokenizer.py "<sql_text>" [version]
118```
119
120The tokenizer supports:
121- Version-specific ClickHouse keywords (24.8: 571, 23.3: 462, case-insensitive)
122- ClickHouse-specific tokens: `::` (typecast), `->` (arrow/lambda), `||` (concatenation),
123 `<=>` (NULL-safe equality, 24.8 only), `<>` / `!=` (not equals)
124- Literals: strings (single-quoted), numbers (int/float/hex), identifiers (bare/backtick/quoted)
125- Comment skipping (-- single line, /* */ multi-line with nesting support)
126- Compound keyword recognition (ORDER BY, GROUP BY, CREATE TABLE, etc.)
127- Error detection (unclosed strings, invalid characters, etc.)
128
129### Step 3: Statement Recognition & Parsing
130
131Run the parser to identify statement type and detect syntax errors.
132
133```bash
134python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_parser.py "<sql_text>" [version]
135```
136
137The parser supports major statement types:
138- **DML**: SELECT (with all ClickHouse extensions), INSERT, INSERT SELECT, DELETE, UPDATE, OPTIMIZE
139- **DDL**: CREATE TABLE/DATABASE/VIEW/MATERIALIZED VIEW/DICTIONARY/FUNCTION/INDEX,
140 ALTER TABLE (all actions), DROP, RENAME, ATTACH, DETACH, UNDROP, CHECK, DESCRIBE
141- **DCL**: GRANT, REVOKE
142- **TCL**: BEGIN TRANSACTION, COMMIT, ROLLBACK, SET TRANSACTION SNAPSHOT
143- **Utility**: EXPLAIN, SHOW, SET, KILL, SYSTEM, BACKUP, RESTORE, WATCH, USE
144
145ClickHouse-specific syntax:
146- `SELECT`: SAMPLE, FINAL, ARRAY JOIN, PREWHERE, GLOBAL JOIN, ASOF JOIN,
147 WITH FILL, INTERPOLATE, WITH TIES, TOP N, LIMIT BY, WITH TOTALS/ROLLUP/CUBE,
148 WINDOW, QUALIFY (24.8 only), GROUP BY ALL, ORDER BY ALL, DISTINCT ON, FETCH FIRST/NEXT
149- `CREATE TABLE`: ENGINE, ORDER BY, PARTITION BY, PRIMARY KEY, SAMPLE BY,
150 TTL, SETTINGS, CODEC, STATISTICS, PROJECTION, CONSTRAINT
151- `ALTER TABLE`: ADD/MODIFY/DROP/RENAME/CLEAR/MATERIALIZE COLUMN,
152 ADD/DROP/CLEAR/MATERIALIZE INDEX/PROJECTION/STATISTICS,
153 partition operations (DROP/DETACH/ATTACH/MOVE/REPLACE/FETCH/FREEZE PARTITION)
154- `SYSTEM`: RELOAD/FLUSH/START/STOP/DROP/SYNC/ENABLE/DISABLE command families
155- `BACKUP/RESTORE`: TABLE/DATABASE/DICTIONARY/ALL TO/FROM Disk/File/S3/Azure
156
157### Step 4: Syntax Check
158
159Based on tokenization and parsing results, execute syntax check rules.
160
161**Syntax Check Rules**:
162
163| Rule ID | Name | Level | Description |
164|---------|------|-------|-------------|
165| SYN-ERR | Lexical Error | ERROR | Unrecognized characters, unclosed strings/comments |
166| SYN001 | Invalid Keyword | ERROR | Keyword not supported by the selected ClickHouse version |
167| SYN002 | Reserved Keyword as Identifier | WARNING | Reserved keyword used as identifier without quoting |
168| SYN003 | Missing Required Clause | ERROR | Missing required clause (e.g., SELECT without column list) |
169| SYN004 | Clause Ordering Error | ERROR | SQL clause order does not conform to grammar |
170| SYN005 | Unclosed String | ERROR | String literal not properly closed |
171| SYN006 | Unclosed Comment | ERROR | Multi-line comment not properly closed |
172| SYN007 | Unclosed Identifier | ERROR | Quoted identifier not properly closed |
173| SYN008 | Invalid Number Format | ERROR | Malformed number literal |
174| SYN009 | Unexpected Character | ERROR | Unrecognized character in SQL text |
175| SYN010 | CREATE TABLE Missing ENGINE | WARNING | CREATE TABLE without ENGINE clause |
176| SYN011 | MergeTree Missing ORDER BY | WARNING | MergeTree family table without ORDER BY |
177| SYN012 | DELETE Missing WHERE | WARNING | DELETE without WHERE clause |
178| SYN013 | UPDATE Missing WHERE | WARNING | UPDATE without WHERE clause |
179| SYN014 | Invalid JOIN Syntax | ERROR | Invalid JOIN combination (e.g., CROSS with ANY) |
180| SYN015 | Unclosed Parenthesis | ERROR | Unbalanced parentheses |
181
182### Step 4b: Specification Check
183
184Based on the MRS ClickHouse development specification (v01, 2026-07-03), execute 35
185specification rules. Use `spec` or `all` mode to enable. Spec rules are version-independent.
186
187**Specification Check Rules (SPEC001-SPEC035)**:
188
189| Rule ID | Name | Level | Category | Description |
190|---------|------|-------|----------|-------------|
191| SPEC001 | Buffer engine prohibited | ERROR | DDL | Buffer engine risks data loss on restart/fault |
192| SPEC002 | Recommend Replicated engine | WARNING | DDL | Recommend Replicated*MergeTree for reliability |
193| SPEC003 | Non-standard table name | WARNING | DDL | Table name should start with letter, alphanumeric+underscore |
194| SPEC004 | String type for date/time prohibited | WARNING | DDL | Use Date/DateTime types instead of String for dates |
195| SPEC005 | String type for numbers prohibited | WARNING | DDL | Use numeric types instead of String for numbers |
196| SPEC006 | Too many Nullable columns | INFO | DDL | Too many Nullable columns waste memory |
197| SPEC007 | Numeric type not minimized | INFO | DDL | Use smallest sufficient numeric type |
198| SPEC008 | LowCardinality not used for low-cardinality | INFO | DDL | Use LowCardinality for columns with cardinality < 100k |
199| SPEC009 | Table exceeds 5000 columns | WARNING | DDL | Single table should not exceed 5000 columns |
200| SPEC010 | Missing TTL lifecycle | INFO | DDL | Tables should have TTL or periodic partition cleanup |
201| SPEC011 | Too many ORDER BY fields | WARNING | DDL | ORDER BY should have <= 4 fields, not null |
202| SPEC012 | PRIMARY KEY not prefix of sort key | WARNING | DDL | PRIMARY KEY should be prefix of ORDER BY |
203| SPEC014 | DROP/ALTER without NO DELAY | INFO | DDL | Add NO DELAY for immediate execution |
204| SPEC015 | Skip indexes exceed 5 per table | WARNING | DDL | Keep skip indexes <= 5 per table |
205| SPEC016 | Excessive partition count risk | INFO | DDL | Keep partitions <= 10000, use integer partition column |
206| SPEC017 | Non-standard MV naming | INFO | DDL | Aggregation tables: _{type}_agg, MVs: _{type}_mv |
207| SPEC018 | MV without explicit target table | WARNING | DDL | Use TO keyword to specify target table for MV |
208| SPEC019 | POPULATE for MV creation prohibited | ERROR | DDL | POPULATE risks data loss during creation |
209| SPEC020 | MV missing TTL | INFO | DDL | MV target table should have TTL matching source |
210| SPEC021 | INSERT into distributed table | WARNING | DML | Write to local tables, not distributed tables |
211| SPEC022 | INSERT not limited to single partition | INFO | DML | Batch inserts should target single partition |
212| SPEC023 | Kafka engine prohibited | ERROR | DML | Avoid ClickHouse Kafka engine, consume in app instead |
213| SPEC024 | SELECT * query prohibited | WARNING | Query | Specify columns explicitly, avoid SELECT * |
214| SPEC025 | Recommend uniqCombined over distinct | INFO | Query | uniqCombined is faster than countDistinct/distinct |
215| SPEC026 | Distributed JOIN without GLOBAL | WARNING | Query | Use GLOBAL JOIN/IN/NOT IN for distributed queries |
216| SPEC027 | Complex multi-table JOIN not split | INFO | Query | Split complex multi-table JOINs into two-table joins |
217| SPEC028 | JOIN order: large table join small table | INFO | Query | Large table JOIN small table, small table on right |
218| SPEC029 | Use FINAL with caution | INFO | Query | FINAL triggers full merge, use sparingly |
219| SPEC030 | Use DELETE/UPDATE mutation with caution | WARNING | DML | Mutations are slow and block merge, use sparingly |
220| SPEC031 | Modify index columns prohibited | ERROR | DML | Never UPDATE ORDER BY / PRIMARY KEY columns |
221| SPEC032 | Use OPTIMIZE with caution | INFO | DML | OPTIMIZE forces merge, runs in off-peak hours |
222| SPEC033 | Batch cleanup not via partition | INFO | DML | Batch cleanup via DROP PARTITION |
223| SPEC034 | Decimal type mismatch in type-sensitive functions | WARNING | Query | Decimal scale/precision mismatch in coalesce/ifNull/nullIf causes implicit conversion |
224| SPEC035 | IN/NOT IN column count mismatch | ERROR | Query | Column count mismatch between left and right sides of IN/NOT IN causes runtime errors or logic errors |
225
226### Step 5: Generate Report
227
228Use the check engine to generate a Markdown format report:
229
230```bash
231python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_checker.py "<sql_text>" [syntax|spec|all] [version]
232```
233
234## 4. Core Commands
235
236### 4.1 Full Check (Recommended)
237
238Run complete syntax + specification check:
239
240```bash
241python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_checker.py "<sql_text>" all 24.8
242```
243
244### 4.2 Syntax Check Only
245
246```bash
247python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_checker.py "<sql_text>" syntax 24.8
248```
249
250### 4.3 Specification Check Only
251
252```bash
253python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_checker.py "<sql_text>" spec 24.8
254```
255
256### 4.4 Tokenization Debug
257
258Inspect token stream for debugging:
259
260```bash
261python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_tokenizer.py "<sql_text>" 24.8
262```
263
264### 4.5 Parser Debug
265
266Inspect parsed statement structure:
267
268```bash
269python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_parser.py "<sql_text>" 24.8
270```
271
272### 4.6 Python API Usage
273
274```python
275from ck_sql_checker import check_sql_markdown
276report = check_sql_markdown("SELECT * FROM t1", "all", "24.8")
277print(report)
278```
279
280## 5. Parameters
281
282| Parameter | Required/Optional | Description | Default |
283|-----------|-------------------|-------------|---------|
284| `sql_text` | Required | SQL statement to check | N/A |
285| `version` | Required | ClickHouse kernel version: 24.8, 23.3, 22.3 | No default; user must select on first invocation per session, reused within session |
286| `check_mode` | Optional | Check mode: syntax/spec/all | syntax |
287
288## 6. Output Format
289
290Report format:
291
292```markdown
293# ClickHouse SQL Check Report
294
295**Check Time**: 2026-07-27T10:00:00
296**ClickHouse Version**: 24.8
297**Statement Type**: SELECT
298**Check Mode**: all
299
300## Summary
301
302| Metric | Value |
303|--------|-------|
304| Total Rules | 51 |
305| Passed | 48 |
306| Violations | 3 |
307| Errors (ERROR) | 1 |
308| Warnings (WARNING) | 1 |
309| Infos (INFO) | 1 |
310
311## Syntax Check
312
313### [X] SYN011: MergeTree Missing ORDER BY
314- **Level**: WARNING
315- **Position**: Line 1, Column 1
316- **Description**: MergeTree family table without ORDER BY clause
317- **Fix Suggestion**: Add ORDER BY (column1, column2, ...)
318
319## Specification Check
320
321### [!] SPEC010: Missing TTL lifecycle
322- **Level**: INFO
323- **Position**: Line 1, Column 1
324- **Description**: Tables should have TTL or periodic partition cleanup
325- **Fix Suggestion**: Add TTL column + toIntervalMonth(N) clause
326
327## Original SQL
328
329```sql
330{original_sql}
331```
332```
333
334**IMPORTANT: Always present check results in table format**, not as bullet lists or
335paragraphs. When checking one or multiple SQL statements, always use three tables:
3361. A **violation detail table** (columns: Rule ID, Rule Name, Level, SQL, Position, Description, Fix Suggestion)
3372. A **summary table** (columns: metrics like total rules, passed, violations, ERROR/WARNING/INFO counts, per SQL)
3383. A **fix suggestion table** (columns: SQL, Issue, Suggestion)
339
340This table format is mandatory for all SQL check outputs.
341
342## 7. Verification Methods
343
344### 7.1 Verify Tokenization
345
346Run the tokenizer independently to verify keyword recognition:
347
348```bash
349python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_tokenizer.py "SELECT * FROM t1 FINAL" 24.8
350```
351
352Expected: Token stream should include `FINAL` as a recognized keyword for version 24.8.
353
354### 7.2 Verify Parser Recognition
355
356Run the parser to verify statement type identification:
357
358```bash
359python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_parser.py "CREATE TABLE t (a UInt32) ENGINE = MergeTree ORDER BY a" 24.8
360```
361
362Expected: Output should show `statement_type: CREATE_TABLE` with parsed column and ENGINE info.
363
364### 7.3 Verify Version-Specific Keywords
365
366Test that version-specific keywords are correctly recognized:
367
368| Keyword | 24.8 | 23.3 | 22.3 |
369|---------|------|------|------|
370| QUALIFY | ✅ | ❌ | ❌ |
371| INTERPOLATE | ✅ | ✅ | ❌ |
372| UNDROP | ✅ | ✅ | ❌ |
373| GROUP BY ALL | ✅ | ✅ | ❌ |
374
375Run tokenizer with different versions to confirm keyword availability.
376
377### 7.4 Verify Spec Rules
378
379Run spec check on known violations to confirm rule detection:
380
381```bash
382# Should trigger SPEC024 (SELECT * prohibited)
383python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_checker.py "SELECT * FROM t1" spec 24.8
384
385# Should trigger SYN011 (MergeTree missing ORDER BY)
386python ~/.cac/skills/huawei-cloud-mrs-clickhouse-sql-check/scripts/ck_sql_checker.py "CREATE TABLE t (a UInt32) ENGINE = MergeTree" spec 24.8
387```
388
389## 8. Best Practices
390
3911. **Run syntax check first** to catch basic errors, then spec check for deeper analysis
3922. **Always specify the ClickHouse version** matching your target cluster to ensure accurate keyword and grammar validation
3933. **Use `all` mode for comprehensive checking** before production deployment
3944. **Pay attention to version-specific keywords** (e.g., QUALIFY is 24.8+ only, INTERPOLATE is 23.3+ only)
3955. **For distributed tables**, check SPEC026 (GLOBAL JOIN) and SPEC021 (INSERT into distributed)
3966. **For MergeTree tables**, always verify ORDER BY (SYN011) and consider TTL (SPEC010)
3977. **For Materialized Views**, follow SPEC017-SPEC020: naming convention, explicit target table, no POPULATE, matching TTL
398
399## 9. References
400
401| Document | Description |
402|----------|-------------|
403| [Keywords v24.8](rules/v24.8/keywords.py) | 571 ClickHouse 24.8 keyword definitions |
404| [Keywords v23.3](rules/v23.3/keywords.py) | 462 ClickHouse 23.3 keyword definitions |
405| [Keywords v22.3](rules/v22.3/keywords.py) | 422 ClickHouse 22.3 keyword definitions |
406| [Token Types v24.8](rules/v24.8/token_types.py) | 24.8 lexer token type definitions |
407| [Token Types v23.3](rules/v23.3/token_types.py) | 23.3 lexer token type definitions |
408| [Token Types v22.3](rules/v22.3/token_types.py) | 22.3 lexer token type definitions |
409| [Grammar v24.8](rules/v24.8/grammar_rules.py) | 24.8 statement type grammar definitions |
410| [Grammar v23.3](rules/v23.3/grammar_rules.py) | 23.3 statement type grammar definitions |
411| [Grammar v22.3](rules/v22.3/grammar_rules.py) | 22.3 statement type grammar definitions |
412| [Spec Rules](rules/common/spec_rules.py) | 35 development specification rules (SPEC001-SPEC035) |
413| [Token Types Ref](references/token_types.md) | Token type reference documentation |
414| [SELECT Grammar](references/select_grammar.md) | SELECT statement grammar reference |
415| [DDL Grammar](references/ddl_grammar.md) | DDL statement grammar reference |
416| [DML Grammar](references/dml_misc_grammar.md) | DML and utility statement grammar reference |
417
418## 10. Notes
419
4201. **Syntax check** does not require cluster connection, can run offline
4212. **Multi-version**: Each version's rules are independently stored; adding a new version
422 does not affect existing versions
4233. **Keywords** are extracted directly from the corresponding ClickHouse kernel source
4244. **Grammar rules** cover 47 statement types from the kernel's Parser classes
4255. **Specification rules** (35 rules, SPEC001-SPEC035) are derived from
426 MRS Development Specification v01 (2026-07-03) Chapter 1: ClickHouse Application Development
427 Standards, covering DDL table design, DDL operations, materialized views, DML
428 data loading, query standards, and data modification standards
4296. Some spec rules (e.g., partition count, data volume, JOIN order) require
430 runtime information and are approximated with static heuristics
4317. The check engine includes a custom tokenizer and statement recognizer,
432 no external SQL parsing libraries required
433
434### Directory Structure
435
436```
437rules/
438 common/
439 spec_rules.py # Version-independent dev-spec rules (SPEC001-SPEC035)
440 v24.8/
441 keywords.py # 571 keywords (from CommonParsers.h APPLY_FOR_PARSER_KEYWORDS)
442 grammar_rules.py # 47 statement types
443 token_types.py # 52 token types (includes Spaceship <=>)
444 v23.3/
445 keywords.py # 462 keywords (from Parser*.cpp ParserKeyword("...") calls)
446 grammar_rules.py # 47 statement types (no QUALIFY/PASTE JOIN/MODIFY REFRESH)
447 token_types.py # 49 token types (no Spaceship/Caret/Ellipsis)
448 v22.3/
449 keywords.py # 422 keywords (from Parser*.cpp ParserKeyword("...") calls)
450 grammar_rules.py # 46 statement types (no UNDROP/INTERPOLATE/GROUP BY ALL/Named Collections)
451 token_types.py # 48 token types (no Spaceship/Caret/Ellipsis/PipeMark)
452scripts/
453 version_loader.py # Dynamic version module loader
454 ck_sql_tokenizer.py # Tokenizer (version-aware via init_version())
455 ck_sql_parser.py # Parser (version-aware via init_version())
456 ck_sql_checker.py # Check engine (version-aware)
457```
458
459To add a new ClickHouse version:
4601. Create `rules/v{version}/` directory
4612. Extract keywords, grammar_rules, token_types from that version's kernel source
4623. The skill automatically detects and supports the new version