Skip to content

Repository files navigation

ClickHouse SQL Parser

GitHub CI LICENSE GoDoc Coverage Status Featured|HelloGitHub

The goal of this project is to build a ClickHouse SQL parser in Go with the following key features:

  • Parse ClickHouse SQL into AST
  • Beautify ClickHouse SQL format

This project is inspired by memefish which is a SQL parser for Spanner in Go.

How to use

You can use it as your Go library or CLI tool, see the following examples:

  • Use clickhouse-sql-parser as a Go library
package main

import (
    clickhouse "github.com/AfterShip/clickhouse-sql-parser/parser"
)

query := "SELECT * FROM clickhouse"
parser := clickhouse.NewParser(query)
// Parse query into AST
statements, err := parser.ParseStmts()
if err != nil {
    return nil, err
}
  • Install clickhouse-sql-parser as a CLI tool

On Linux:

$ go install github.com/AfterShip/clickhouse-sql-parser@latest

On macOS:

$ brew install clickhouse-sql-parser

Parse ClickHouse SQL into AST or format ClickHouse SQL:

## Parse query into AST
$ clickhouse-sql-parser "SELECT * FROM clickhouse WHERE a=100"

## Format query (compact, single-line output)
$ clickhouse-sql-parser -format "SELECT * FROM clickhouse WHERE a=100"

## Beautify query (formatted with proper indentation and line breaks)
$ clickhouse-sql-parser -beautify "SELECT * FROM clickhouse WHERE a=100"

## Parse query from file
$ clickhouse-sql-parser -f ./test.sql

Beautify SQL Example

The -beautify flag formats SQL with proper indentation and line breaks, making complex queries more readable:

# Input (compact, hard to read)
$ clickhouse-sql-parser -beautify "SELECT user_id, COUNT(*) AS total, AVG(amount) AS avg_amount FROM orders WHERE status='completed' AND created_at>'2024-01-01' GROUP BY user_id HAVING COUNT(*)>5 ORDER BY total DESC LIMIT 10"

# Output (beautified, easy to read)
SELECT
  user_id,
  COUNT(*) AS total,
  AVG(amount) AS avg_amount
FROM orders
WHERE
  status = 'completed'
AND
  created_at > '2024-01-01'
GROUP BY
  user_id
HAVING COUNT(*) > 5
ORDER BY
  total DESC
LIMIT 10
  • Parsed tree(AST) back into a SQL statement
parser := clickhouse.NewParser("SELECT * FROM clickhouse")
// Parse query into AST
statements, err := parser.ParseStmts()
if err != nil {
    return nil, err
}

// Format AST back into a SQL string
for _, stmt := range statements {
  fmt.Println(clickhouse.Format(stmt))
}

AST Traversal

Walk Pattern (Recommended)

The Walk pattern provides a simple and efficient way to traverse AST nodes. Use the Walk function to visit all nodes in the AST:

import (
    clickhouse "github.com/AfterShip/clickhouse-sql-parser/parser"
)

parser := clickhouse.NewParser("SELECT * FROM table WHERE id = 1")
statements, err := parser.ParseStmts()
if err != nil {
    return err
}

// Walk through all nodes in the AST
clickhouse.Walk(statements[0], func(node clickhouse.Expr) bool {
    fmt.Printf("Node type: %T\n", node)
    return true // return false to stop traversal for this subtree
})

Walk Pattern Functions

  • Walk(node Expr, fn WalkFunc) - Traverses all nodes in depth-first order
  • WalkWithBreak(node Expr, fn WalkFunc) - Allows early termination of traversal
  • Find(root Expr, predicate func(Expr) bool) - Finds the first node matching a condition
  • FindAll(root Expr, predicate func(Expr) bool) - Finds all nodes matching a condition
  • Transform(root Expr, transformer func(Expr) Expr) - Applies transformations to nodes

Examples

Find all table identifiers:

tables := clickhouse.FindAll(stmt, func(node clickhouse.Expr) bool {
    _, ok := node.(*clickhouse.TableIdentifier)
    return ok
})

Find the first WHERE clause:

whereClause, found := clickhouse.Find(stmt, func(node clickhouse.Expr) bool {
    _, ok := node.(*clickhouse.WhereClause)
    return ok
})

Update test assets

For the files inside output and format dir are generated by the test cases,

if you want to update them, you can run the following command:

$ make update_test

Benchmarks

See docs/benchmarks.md for how to run the benchmarks and the latest results.

Projects Using clickhouse-sql-parser

Feel free to open a PR and add your projects here:

  • SigNoz: OpenTelemetry-native observability platform with logs, metrics and traces in one tool.
  • Unkey: The developer platform for modern APIs.
  • Akvorado: Flow collector, enricher and visualizer.
  • Trickster: HTTP reverse proxy cache and time series database query accelerator.
  • Measure: Open source mobile monitoring for crashes, ANRs and performance issues.
  • Clawpatrol: Security firewall for agents.
  • Logchef: Lightweight, single-binary log analytics interface for ClickHouse.
  • Substreams: Blockchain streaming data engine based on StreamingFast Firehose technology.
  • Altinity MCP: Model Context Protocol server to use ClickHouse databases in your AI agents.

For AI coding agents

If you are an AI coding agent (or are using one) to contribute to this project, read AGENTS.md first and use it as your working context. It covers the project structure, coding style, testing workflow, and contribution practices — including validating SQL against clickhouse-local before adding new syntax or fixing parsing issues.

Contact us

Feel free to open an issue or discussion if you have any issues or questions.

About

Go library and CLI that parses ClickHouse-dialect SQL into a typed AST. Supports lexing, parsing, AST walking, round-trip formatting, and beautification. Use for query linting, static analysis, rewriting, access-control enforcement, schema validation, and SQL formatting.

Topics

Resources

Stars

247 stars

Watchers

5 watching

Forks

Releases

Packages

Used by

Contributors

Languages