4 releases
Uses new Rust 2024
| 0.0.4 | Jan 29, 2026 |
|---|---|
| 0.0.3 | Jan 26, 2026 |
| 0.0.2 | Jan 25, 2026 |
| 0.0.1 | Jan 25, 2026 |
#1391 in Parser implementations
60MB
1M
SLoC
pg-parser-rs
PostgreSQL-flavored SQL parser based on tree-sitter, with a Rust AST layer.
Features
- Exposes the SQL
Languagefor tree-sitter - Provides a simple
parsehelper and aPgParserwrapper - Builds a PG-flavored AST for SELECT/INSERT/UPDATE/DELETE
Install
cargo add pg-parser-rs
Usage (Rust)
let mut parser = tree_sitter::Parser::new();
parser.set_language(&pg_parser_rs::language())?;
let tree = parser.parse("SELECT 1;", None).unwrap();
Or use the wrapper for a simpler API:
let mut parser = pg_parser_rs::PgParser::new()?;
let tree = parser.parse("SELECT 1;").unwrap();
API (AST + Diagnostics)
Parse into typed AST:
let statements = pg_parser_rs::parse_statements("SELECT 1;");
Parse and collect diagnostics (syntax + unsupported):
let result = pg_parser_rs::parse_statements_with_diagnostics("SELECT FROM t");
for err in result.errors {
println!("{:?} {:?}", err.kind, err.span);
}
Parse a single query with diagnostics:
let (query, errors) = pg_parser_rs::parse_query_with_diagnostics("SELECT * FROM t");
Node types JSON (for tooling):
let json = pg_parser_rs::NODE_TYPES;
Architecture
- Parsing: tree-sitter builds a concrete syntax tree (CST) from SQL input.
- AST:
ast_builderwalks the CST and produces a typed AST insrc/ast.rs. - Scope: SELECT/CTE/query expressions plus DML (INSERT/UPDATE/DELETE); unsupported syntax maps to
Statement::Unknown. - Extensibility:
#[non_exhaustive]on key enums andUnknownvariants allow incremental support.
Example: traverse and extract AST nodes
use pg_parser_rs::{parse_statements, Expr, SelectItem, Statement};
fn main() {
let sql = "SELECT a, b + 1 AS c FROM t WHERE b > 10 ORDER BY c DESC";
let statements = parse_statements(sql);
for stmt in statements {
if let Statement::Query(query) = stmt {
if let pg_parser_rs::SetExpr::Select(select) = query.body {
for item in select.projection {
match item {
SelectItem::UnnamedExpr(expr) | SelectItem::ExprWithAlias { expr, .. } => {
if let Expr::Identifier(ident) = expr {
println!("select column: {}", ident.value);
}
}
_ => {}
}
}
}
}
}
}
Notes
The grammar lives under grammar/ and is compiled via build.rs.
Generated sources (grammar/src/parser.c, grammar/src/node-types.json,
grammar/src/grammar.json) are not checked into the repo.
Build requirements
This crate runs tree-sitter generate during build. Install the CLI:
cargo install tree-sitter-cli
You can also point TREE_SITTER_CLI to a custom binary.
Development flow
After changing grammar/grammar.js or grammar/src/scanner.cc, regenerate:
tree-sitter generate
Then sync generated sources into generated/ for builds and packaging:
mkdir -p generated/tree_sitter
cp grammar/src/parser.c generated/
cp grammar/src/scanner.cc generated/
cp grammar/src/node-types.json generated/
cp grammar/src/grammar.json generated/
cp grammar/src/tree_sitter/*.h generated/tree_sitter/
License
Apache-2.0 (see LICENSE).
Dependencies
~2.7–4MB
~78K SLoC