Hive sql (HQL)解析,已知的方法 有
-
jsqlparser - 失败了,不支持 hive 语法
-
hive-exec ,用 ParseDriver 和 ast token , 失败了,复杂语法不支持(奇怪,hive 服务器难道不是用的这个解析吗)
这里有一些 使用案例,人家用的好好的,可能是我们的姿势不对,待研究 -
优步 Uber 的queryparser,使用
haskell
语言开发,没有maven jar 包可用,算了,咱也不熟悉 -
gsp - general sql parser ,商业收费,测试案例jar包可以下载和执行,说明源码也是可用的。
翻看源码,发现其中使用了 dbeaver 的 jkiss 等package, 明显是"借鉴了" dbeaver 开源git 上 的一部分代码。TGSqlParser sqlparser = new TGSqlParser(EDbVendor.dbvhive); sqlparser.sqltext = "SELEct 1" ; int ret = sqlparser.parse(); if (ret == 0){ for(int i=0;i<sqlparser.sqlstatements.size();i++){ analyzeStmt(sqlparser.sqlstatements.get(i)); System.out.println(""); } } else { System.out.println(sqlparser.getErrormessage()); }
虽然功能很强大,但是尚未研究透怎么移植到 项目中 。 有人说可以直接build 到项目中,待研究
-
自定义解析代码,需要自己写解析逻辑 ,比如 。 这个 太费时间了,毕竟bug多,有成型的持续团队维护的最好了。
-
alibaba druid
- 经过不断迭代,已经解决了很多 hive解析的bug,比如 2020年的
create table
bug - 支持的db type 多,impala ,hive ,oracle 等等都支持 。
- 缺点就是捆绑销售,1个jar 包高大全的 datasource 全家桶。我们只是想要 parser 而已。
- 老版本的 sql 解析会有bug,但是新版本的已经解决。测试了 一些复杂 语句,都能正确 解析。
对比 hive 本身的 parser ast 的操作,还需要自己分析 token,实在是太那个了。
二者对比参考代码
/** * hive-sql-parser versus druid-sql-parser */ @Test public void testDruidSqlParser() throws ParseException { String sql = "FROM (SELECT p.datekey datekey, p.userid userid, c.clienttype FROM detail.usersequence_client c JOIN fact.orderpayment p ON p.orderid = c.orderid JOIN default.user du ON du.userid = p.userid WHERE p.datekey = 20131118 ) base INSERT OVERWRITE TABLE `test`.`customer_kpi` SELECT base.datekey, base.clienttype, count(distinct base.userid) buyer_count GROUP BY base.datekey, base.clienttype"; final SQLStatementParser hive = SQLParserUtils.createSQLStatementParser(sql, DbType.hive); final SQLStatement statement = hive.parseStatement(); System.out.println(statement); // as you can see , using this parseDriver will cause an error ParseDriver pd = new ParseDriver(); ASTNode ast = pd.parse(sql); System.out.println(ast.dump()); }
- 经过不断迭代,已经解决了很多 hive解析的bug,比如 2020年的
/**
* @return 解析树
*/
public static List<SQLStatement> parseStatements(String sql, String dbType) {
try {
return SQLUtils.parseStatements(sql, dbType);
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new RuntimeException("SQL格式错误");
}
}
/*
* sql格式化
*/
public static void format(String sql, String dbType) {
String sqlFormat = SQLUtils.format(sql, dbType);
if (sql.equals(sqlFormat)) {
throw new RuntimeException("SQL格式错误");
}
}