JSqlParserTurn any SQL statement into a traversable tree of Java objects -- and back again.An RDBMS-agnostic SQL parser for the JVM: |
|
JSqlParser is a free, open source databases project written in Java and released under Apache-2.0. It has 5,964 GitHub stars, 1,430 forks and 12 open issues, and was last pushed 27 hours ago. On this registry it ranks #128 of 203 tracked projects in Databases, with 5 head-to-head comparisons available.
What is JSqlParser?
JSqlParser is an Apache-2.0 Java library that turns any SQL statement into a traversable hierarchy of Java classes and back again, aimed at JVM developers who need to read, analyse, rewrite, or generate SQL as data rather than execute it.
What it is
JSqlParser lives in the JVM database-tooling ecosystem and is published to Maven Central. It is an RDBMS-agnostic SQL parser: one grammar covering twelve dialects, with no native extensions. It takes SQL text and produces an abstract syntax tree built from Java objects such as PlainSelect, SelectItem, Table, EqualsTo, Column, and LongValue. That tree can be navigated with the Visitor pattern, and the same object model works in reverse, so statements can be built from Java through a fluent API and rendered back into SQL text.
The concrete problem it solves is the parsing layer itself. Applications that need to inspect, filter, rewrite, or generate SQL normally end up with regular expressions, hand-rolled string manipulation, or a parser tied to a single database vendor. JSqlParser replaces that with one Java dependency and one grammar that spans the dialects named in its topic list, including MySQL, Oracle, PostgreSQL, and SQL Server.
Key capabilities
- Parse a statement with
CCJSqlParserUtil.parse(sqlStr), then read the tree through typed accessors:getSelectItems(),getFromItem(),getWhere(). - Navigate the resulting hierarchy with the Visitor pattern, which is the intended traversal mechanism.
- Build statements in the opposite direction using a fluent Java API and render them back out as SQL text.
- Handle one grammar across twelve dialects through an RDBMS-agnostic design with no native extensions.
- Cover vendor syntax tagged in the topic list: mysql, oracle, postgresql, sqlserver.
- Run on continuously released Manticore builds, benchmarked 11x faster than 5.3 —
JSQLParserBenchmark.parseSQLStatementsmeasures 32.525 ms/op on the latest line against 983.459 ms/op on 5.3, and the README reports it 19x ahead ofsqlglot[c]on JSqlParser's ownSELECTtest suite. - Ship under Apache-2.0, with CI, Coveralls coverage, and Codacy badges plus a wiki, samples page, syntax reference, and changelog.
Who uses it and how
- JVM teams that must inspect or rewrite SQL before it reaches a database: proxies, migration tooling, formatters, auditing, and lineage analysis.
- Multi-dialect shops where one code path has to cope with MySQL, Oracle, PostgreSQL, and SQL Server syntax at once.
- Java applications that need to generate SQL programmatically rather than concatenate strings, using the fluent builder and text rendering.
- Projects assessing adoption signals can note 5,964 stars, 1,430 forks, and 12 open issues, with the topic list carrying
paypalalongsideast,hierarchy, andsql-statement.
Getting started
Add the Maven coordinate com.manticore-projects.jsqlformatter:jsqlparser with version range [5.3.218,), or in Gradle implementation("com.manticore-projects.jsqlformatter:jsqlparser:+"), for the continuously released stable builds. The upstream com.github.jsqlparser:jsqlparser release, currently 5.3, is also on Maven Central, and snapshot coordinates plus repository setup are documented on the build dependencies page.
How it compares
The README names only sqlglot[c] as a comparison point, reporting JSqlParser 19x ahead on its own SELECT test suite and describing it as the fastest parser tested on real-world SQL in any language. Within this registry it is the JVM-native option for the same job other languages solve with their own parser libraries: a single embedded dependency that produces a walkable tree instead of a service.
When to use it — and when not to
Use it when the JVM is the target platform and SQL needs to be treated as a manipulable tree, whether for analysis, rewriting, or generation. Be aware that the two distribution lines differ sharply in freshness: the README states the upstream com.github.jsqlparser release on Maven Central is considerably older than the Manticore builds, so the coordinate choice matters. It is a parser only — it does not execute queries, connect to a database, or run as a service, and there is no Docker image, compose file, or hosted option, so anyone wanting an out-of-process SQL analysis service has to build that layer themselves.
project readme (upstream, from github) — read inline
Website · Samples · Syntax · Change Log · Contributing
What it does
Give it SQL. Get an AST you can walk, rewrite, and print back out.
SELECT 1 FROM dual WHERE a = b
SQL Text
└─Statements: statement.select.PlainSelect
├─selectItems: statement.select.SelectItem
│ └─LongValue: 1
├─Table: dual
└─where: expression.operators.relational.EqualsTo
├─Column: a
└─Column: b
String sqlStr = "select 1 from dual where a=b";
PlainSelect select = (PlainSelect) CCJSqlParserUtil.parse(sqlStr);
SelectItem selectItem = select.getSelectItems().get(0);
Assertions.assertEquals(new LongValue(1), selectItem.getExpression());
Table table = (Table) select.getFromItem();
Assertions.assertEquals("dual", table.getName());
EqualsTo equalsTo = (EqualsTo) select.getWhere();
Column a = (Column) equalsTo.getLeftExpression();
Column b = (Column) equalsTo.getRightExpression();
Assertions.assertEquals("a", a.getColumnName());
Assertions.assertEquals("b", b.getColumnName());
The tree is traversable with the Visitor pattern, and the same object model works in reverse: build statements from Java with a fluent API and render them as SQL text.
Install
Use the stable Manticore builds. They are released continuously from the current development
line and carry all of the performance and grammar work described below. The upstream
com.github.jsqlparser release on Maven Central is considerably older.
<dependency>
<groupId>com.manticore-projects.jsqlformatter</groupId>
<artifactId>jsqlparser</artifactId>
<version>[5.3.218,)</version>
</dependency>
implementation("com.manticore-projects.jsqlformatter:jsqlparser:+")
Upstream release and snapshots
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>5.3</version>
</dependency>
Snapshot coordinates and repository setup are on the build dependencies page.
Performance
11× faster than 5.3, and the fastest parser on real-world SQL of any of the parsers
tested, in any language — 19× ahead of sqlglot[c] on JSqlParser's own SELECT test suite.
Benchmark (version) Mode Cnt Score Error Units
JSQLParserBenchmark.parseSQLStatements latest avgt 15 32.525 ± 0.413 ms/op
JSQLParserBenchmark.parseSQLStatements 5.3 avgt 15 983.459 ± 8.197 ms/op
JSQLParserBenchmark.parseSQLStatements 5.1 avgt 15 319.601 ± 4.081 ms/op
Methodology and the full cross-parser comparison against SQLGlot, sqlglot[c] and
polyglot-sql: jsqlparser-bench.
What it parses
JSqlParser targets the SQL standard plus all major RDBMS. One grammar covers all of them, and missing syntax gets added on demand — open an issue.
BigQuery · Snowflake · DuckDB · Redshift · Oracle · MS SQL Server · Sybase
PostgreSQL · MySQL · MariaDB · DB2 · H2 · HSQLDB · Derby · SQLite
| Statements | |
|---|---|
| Queries | SELECT · WITH … · Piped SQL |
| ksqlDB windows | JOIN WITHIN, window GRACE PERIOD, and EMIT CHANGES/FINAL |
| ClickHouse column selection | COLUMNS('regexp') select items with chained APPLY, EXCEPT, and REPLACE transformers |
| DML | INSERT · UPDATE · UPSERT · MERGE · DELETE · TRUNCATE TABLE |
| DDL | CREATE … · ALTER … · DROP … |
| PostgreSQL RLS | CREATE POLICY · ALTER TABLE … ENABLE/DISABLE/FORCE/NO FORCE ROW LEVEL SECURITY |
| Informix constraints | ALTER TABLE … ADD CONSTRAINT with trailing constraint names for primary, unique, foreign and check constraints; enable with parser.withDialect(Dialect.INFORMIX) |
| Salesforce SOQL | INCLUDES · EXCLUDES |
Beyond statement shapes, the grammar handles nested sub-selects, bind parameters (?,
:name), window and analytic functions, Oracle hints, and the T-SQL square-bracket versus
array-literal ambiguity. The complete reference is on the
syntax page.
PostgreSQL dollar-quoted strings, including $tag$…$tag$, retain their delimiter and
literal body in StringValue. Tagged quotes are disabled by default to preserve
identifier parsing. Enable them with parser.withDialect(Dialect.POSTGRESQL) or
parser.withDollarQuotedStringTags(true). Untagged $$…$$ literals remain enabled.
Statement classification
Any parsed statement can say what it actually does — no second parse, no visitor to write:
StatementFeatures features = CCJSqlParserUtil.parse(sqlStr).getFeatures();
// safeguard a read-only client before anything reaches the database
if (connection.isReadOnly() && features.mayModifyData()) {
throw new SQLException("rejected: " + features.getUnresolvedReferences());
}
// dispatch correctly
if (features.returnsResultSet()) { statement.executeQuery(sqlStr); }
else { statement.executeUpdate(sqlStr); }
This is not sqlStr.startsWith("SELECT") with extra steps. RETURNING turns DML into a row
source, a data-modifying CTE hides a DELETE inside a SELECT, and INSERT INTO x SELECT ..
contains a query but returns nothing:
| SQL | returns rows | modifies data |
|---|---|---|
SELECT * FROM t |
yes | no |
INSERT INTO x SELECT * FROM t |
no | yes |
DELETE FROM t RETURNING * |
yes | yes |
WITH c AS (DELETE FROM t RETURNING *) SELECT * FROM c |
yes | yes |
SELECT nextval('s') |
yes | unproven |
Features are not mutually exclusive, and each is three-valued: proven, not excludable, or ruled
out. is() answers "did the grammar prove it", may() answers "could it be ruled out" — so a
guard uses may() and a dispatcher uses is(). Function volatility is not a syntactic property,
so anything the caller has not declared pure stays unproven and is listed by name.
Legacy MySQL GROUP BY ... ASC/DESC is available with Dialect.MYSQL and the explicit
withLegacyMySqlGroupBy(true) option; modern/default parsing keeps it disabled.
Piped SQL
Support is progressing for Piped SQL, which writes queries in the order th
readme truncated — read the full docs on github
Frequently asked questions
Is JSqlParser free to use?
JSqlParser is open source under the Apache-2.0 licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.
What does JSqlParser do?
JSqlParser parses an SQL statement and translate it into a hierarchy of Java classes. The generated hierarchy can be navigated using the Visitor Pattern
What is JSqlParser written in?
JSqlParser is primarily written in Java. Its source is publicly available at https://github.com/JSQLParser/JSqlParser, and it has 5,964 GitHub stars.