方案一:使用 Kingbase 官方 JDBC 驱动中的解析工具(仅校验sql语法)
Kingbase 作为 PostgreSQL 的国产分支,提供了兼容的 JDBC 驱动,其中包含 SQL 解析功能:
java
import com.kingbase8.core.Parser;
import com.kingbase8.core.nodes.Node;
// 创建解析器
Parser parser = new Parser();
// 解析 SQL 为 AST 节点
String sql = "SELECT * FROM users WHERE id = 1";
Node astNode = parser.parse(sql);
方案二:使用通用 SQL 解析库(推荐)
由于 Kingbase 兼容 PostgreSQL,可以使用以下成熟的 Java SQL 解析库:
1. JSqlParser(推荐)
java
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.schema.Table;
public class KingbaseSqlParser {
public static void parseSql(String sql) throws Exception {
// 解析 SQL 语句
Statement statement = CCJSqlParserUtil.parse(sql);
if (statement instanceof Select) {
Select select = (Select) statement;
PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
// 获取表名
Table table = (Table) plainSelect.getFromItem();
System.out.println("表名: " + table.getName());
// 获取 WHERE 条件
if (plainSelect.getWhere() != null) {
System.out.println("WHERE 条件: " + plainSelect.getWhere());
}
}
}
public static void main(String[] args) throws Exception {
String sql = "SELECT id, name FROM users WHERE age > 18 AND status = 'active'";
parseSql(sql);
}
}
Maven 依赖:
xml
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>4.9</version>
</dependency>
2. Druid SQL Parser(阿里巴巴开源,支持 Kingbase)
java
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGSchemaStatVisitor;
import java.util.List;
public class KingbaseDruidParser {
public static void parseWithDruid(String sql) {
// Kingbase 使用 PostgreSQL 方言
List<SQLStatement> statements = SQLUtils.parseStatements(sql, "postgresql");
for (SQLStatement statement : statements) {
PGSchemaStatVisitor visitor = new PGSchemaStatVisitor();
statement.accept(visitor);
// 获取表名
System.out.println("表: " + visitor.getTables());
// 获取列
System.out.println("列: " + visitor.getColumns());
}
}
public static void main(String[] args) {
String sql = "SELECT u.id, u.name FROM users u JOIN orders o ON u.id = o.user_id WHERE o.amount > 100";
parseWithDruid(sql);
}
}
Maven 依赖:
xml
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.20</version>
</dependency>
方案三:自定义 AST 节点结构
如果需要更精细的控制,可以定义自己的 AST 节点:
java
// 基础节点接口
public interface SqlNode {
SqlNodeType getType();
List<SqlNode> getChildren();
String toSql();
}
// 枚举类型
public enum SqlNodeType {
SELECT, INSERT, UPDATE, DELETE,
TABLE, COLUMN, WHERE, JOIN,
EXPRESSION, LITERAL, IDENTIFIER
}
// 具体节点实现
public class SelectNode implements SqlNode {
private List<ColumnNode> columns;
private TableNode fromTable;
private WhereNode whereClause;
private List<JoinNode> joins;
@Override
public SqlNodeType getType() {
return SqlNodeType.SELECT;
}
// Getters and setters...
}
// 使用 Druid 构建自定义 AST
public class CustomAstBuilder {
public SqlNode buildAst(String sql) {
List<SQLStatement> statements = SQLUtils.parseStatements(sql, "postgresql");
if (statements.isEmpty()) {
return null;
}
SQLStatement stmt = statements.get(0);
if (stmt instanceof SQLSelectStatement) {
return parseSelect((SQLSelectStatement) stmt);
}
// 处理其他语句类型...
return null;
}
private SqlNode parseSelect(SQLSelectStatement selectStmt) {
SelectNode node = new SelectNode();
SQLSelect select = selectStmt.getSelect();
SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) select.getQuery();
// 解析 SELECT 列表
List<ColumnNode> columns = new ArrayList<>();
for (SQLSelectItem item : queryBlock.getSelectList()) {
columns.add(new ColumnNode(item.toString()));
}
node.setColumns(columns);
// 解析 FROM 子句
SQLTableSource tableSource = queryBlock.getFrom();
if (tableSource instanceof SQLExprTableSource) {
node.setFromTable(new TableNode(((SQLExprTableSource) tableSource).getName().getSimpleName()));
}
// 解析 WHERE 子句
if (queryBlock.getWhere() != null) {
node.setWhereClause(new WhereNode(queryBlock.getWhere().toString()));
}
return node;
}
}
方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| JSqlParser | 轻量、易用、文档丰富 | Kingbase 特有语法支持有限 | 通用 SQL 解析 |
| Druid | 功能强大、支持 PG 方言、性能优秀 | 较重 | 企业级应用、监控分析 |
| 官方驱动 | 完全兼容 Kingbase 语法 | 文档较少 | 深度集成 Kingbase |
Kingbase 特有语法处理
对于 Kingbase 特有的语法(如国产加密、安全策略等),建议使用 Druid 并扩展 Visitor:
java
public class KingbaseVisitor extends PGSchemaStatVisitor {
@Override
public boolean visit(SQLCreateTableStatement x) {
// 处理 Kingbase 特有的表选项
if (x.getTableOptions() != null) {
for (SQLAssignItem option : x.getTableOptions()) {
String name = option.getTarget().toString();
// 处理 ENCRYPTED、SECURITY 等 Kingbase 特有属性
if ("ENCRYPTED".equalsIgnoreCase(name)) {
// 处理加密表
}
}
}
return super.visit(x);
}
}
推荐 :对于大多数场景,使用 Druid SQL Parser 配合 PostgreSQL 方言是最佳选择,既能兼容 Kingbase,又有完善的 AST 访问能力。