目录
市面上有很多做SQL解析的语法引擎,如阿里的druid,ANTLR等。楼主之前在南京某宁公司使用ANTLR和阿里的druid做过表/字段级的血缘解析,也一直认为ANTLR/druid做解析做解析很方便,尤其是ANTLR的visitor模式,想要哪个要哪个。
但近期由于业务的复杂,需要将SQL语法不仅解析出来还需要做一定的转义操作。参考了spark源码是如何处理ANTLR的,结果发现太过复杂(其实是没大看懂),因此采用了最简单的replace方式,可是该方式会存在问题(你们懂的!!)
为此,研究了一下据说很牛逼的Calcite。但不得不承认,Calcite真复杂,目前还只是小白!!
import org.apache.calcite.config.Lex;
import org.apache.calcite.sql.*;
import org.apache.calcite.sql.parser.SqlParser;
import org.apache.calcite.sql.parser.SqlParserPos;
import org.apache.calcite.sql.parser.impl.SqlParserImpl;
import org.apache.calcite.sql.validate.SqlConformanceEnum;
import org.apache.calcite.util.ImmutableBeans;
/**
* Created with IntelliJ IDEA.
* Description:
*
* @Author: yuanhongjun
* DateTime: 2021-04-13 9:25
*/
public class CalciteSQLParser {
private static SqlParser.Config config = SqlParser.configBuilder().setLex(Lex.MYSQL).setCaseSensitive(true).setConformance(SqlConformanceEnum.MYSQL_5).build();
//.setConformance(SqlConformanceEnum.MYSQL_5) limit 10,10
//.setCaseSensitive(true)大小写敏感
private static SqlParser.Config DEFAULT = (ImmutableBeans.create(SqlParser.Config.class)).withLex(Lex.MYSQL).withIdentifierMaxLength(128).withConformance(SqlConformanceEnum.DEFAULT).withParserFactory(SqlParserImpl.FACTORY);
public static void main(String[] args) throws Exception {
// String sql = "select sum(b) as dd , b.c from db.d where e = x and f not in (x,d)";
// String sql = "SELECT sum(x.dd) as xx ,2 from db.a x where id = xx and c = 'zz' group by xx order by dd limit 10 " ;
// String sql = "SELECT sum(x.dd) as xx ,2 from db.a x where id = xx and c = 'zz' order by dd limit 10 ";
// String sql = "SELECT sum(f) as xx,e FROM db.B left join B.dd on dd.xx=b.cc WHERE g = h";
// String sql = "SELECT sum(f) as xx,e FROM db.B left join (select xx from B.dd union select xx from d.dddddd) as bdd on dd.xx=b.cc WHERE g = h";
String sql = "SELECT sum(x.dd) as xx ,2 from db.a x where id = xx and c = 'zz' " +
"union all SELECT sum(f) as xx,e FROM db.B left join B.dd on dd.xx=b.cc WHERE g = h limit 10,10";
//当存在子查询和order by的时候都可能需要传入到Select
SqlParser sqlParser = SqlParser.create(sql, config);
try {
SqlNode sqlNode = sqlParser.parseQuery();
System.out.println(sqlNode.toString());
hanlerSQL(sqlNode);
} catch (Exception e) {
throw new RuntimeException("", e);
}
}
private static void hanlerSQL(SqlNode sqlNode) {
SqlKind kind = sqlNode.getKind();
switch (kind) {
case SELECT:
hanlerSelect(sqlNode);
break;
case UNION:
((SqlBasicCall) sqlNode).getOperandList().forEach(node -> {
hanlerSQL(node);
});
break;
case ORDER_BY:
handlerOrderBy(sqlNode);
break;
}
}
private static void handlerOrderBy(SqlNode node) {
SqlOrderBy sqlOrderBy = (SqlOrderBy) node;
SqlNode query = sqlOrderBy.query;
hanlerSQL(query);
SqlNodeList orderList = sqlOrderBy.orderList;
handlerField(orderList);
}
private static void hanlerSelect(SqlNode select) {
SqlSelect sqlSelect = (SqlSelect) select;
//TODO 改写SELECT的字段信息
SqlNodeList selectList = sqlSelect.getSelectList();
//字段信息
selectList.getList().forEach(list -> {
handlerField(list);
});
handlerFrom(sqlSelect.getFrom());
if (sqlSelect.hasWhere()) {
handlerField(sqlSelect.getWhere());
}
if (sqlSelect.hasOrderBy()) {
handlerField(sqlSelect.getOrderList());
}
SqlNodeList group = sqlSelect.getGroup();
if (group != null) {
group.forEach(groupField -> {
handlerField(groupField);
});
}
SqlNode fetch = sqlSelect.getFetch();
if (fetch != null) {
//TODO limit
}
}
private static void handlerFrom(SqlNode from) {
SqlKind kind = from.getKind();
switch (kind) {
case IDENTIFIER:
//最终的表名
SqlIdentifier sqlIdentifier = (SqlIdentifier) from;
//TODO 表名的替换,所以在此之前就需要获取到模型的信息
System.out.println("==tablename===" + sqlIdentifier.toString());
break;
case AS:
SqlBasicCall sqlBasicCall = (SqlBasicCall) from;
SqlNode selectNode = sqlBasicCall.getOperandList().get(0);
hanlerSQL(selectNode);
break;
case JOIN:
SqlJoin sqlJoin = (SqlJoin) from;
SqlNode left = sqlJoin.getLeft();
hanlerSQL(left);
SqlNode right = sqlJoin.getRight();
hanlerSQL(right);
SqlNode condition = sqlJoin.getCondition();
handlerField(condition);
break;
case SELECT:
hanlerSQL(from);
break;
}
}
private static void handlerField(SqlNode field) {
SqlKind kind = field.getKind();
switch (kind) {
case AS:
SqlNode[] operands_as = ((SqlBasicCall) field).operands;
SqlNode left_as = operands_as[0];
handlerField(left_as);
break;
case IDENTIFIER:
//表示当前为子节点
SqlIdentifier sqlIdentifier = (SqlIdentifier) field;
System.out.println("===field===" + sqlIdentifier.toString());
break;
default:
if (field instanceof SqlBasicCall) {
SqlNode[] nodes = ((SqlBasicCall) field).operands;
for (int i = 0; i < nodes.length; i++) {
handlerField(nodes[i]);
}
}
if (field instanceof SqlNodeList) {
((SqlNodeList) field).getList().forEach(node -> {
handlerField(node);
});
}
break;
}
}
}
代码只是完成了解析的操作,具体怎么封装没有实现,后面会继续研究Calcite的validate以及如何根据不同存储引擎转换成对应的查询语句,敬请期待……
第一部分 回收Thin模式磁盘空间背景:在使用Thin模式的磁盘,空间不停的增加,通过通常的方法删除文件,释放可用空间,在虚拟机中查看已使用空间和在vsphere的存储中查看的已使用空间不一样,存储中的空间好像只会增加不会自动减少,根据搜索的资料总结出来释放可用空间的方法如下环境:Vsphere 6.0第一步: 虚拟机中处理如果是windows系统,请使用sdelete工具进行置零,此工具...
联发科在2014年10月发布了首款集成全网通4G基带的四核处理器-MT6735,后续该处理器衍生MTK6735P/M两个版本,阉割了部分网络性能和降低主频。时间过去快3年了,目前仍有大量新款低端手机采用MT6735,很多消费者开始关注它的性能:够用吗?下面我来详细介绍MT6735参数和性能特点。CPU部分,其采用四核心64位Cortex-A53架构设计,主频1.3-1.5GHz,这和上午我们报道的...
根据报错的关键字,大底的意思就是依赖方面的问题。以下为启动程序时遇到的错误:org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'deleteRedisData': Unsatisfied dependency expressed through f...
最近在Youtube看Docker视频的过程中不幸看到了Mesos的介绍,然后就有一种一见如故的感觉,最终根据mesosphere官网的文档在IBM的Bluemix虚拟机上搭建了基于ZooKeeper + Mesos + Marathon的平台。搭建之前先简单了解下各个组件是做什么的。(来自wikipedia及其他网络)ZooKeeper:Zookeeper
2.2.3、SENSOR_ORIENTATION2.2.4、FLASH_INFO_AVAILABLE2.2.5、SCALER_AVAILABLE_MAX_DIGITAL_ZOOM2.2.6、LENS_INFO_MINIMUM_FOCUS_DISTANCE2.2.7、INFO_SUPPORTED_HARDWARE_LEVEL2.3、CameraDevice类2.4、CameraCaptureSession类2.5、CameraRequest类0、相关文章:=======Android C
添加定义 USE_STDPERIPH_DRIVER
线性插值或 Lerp 函数会返回一个基于 Alpha 输入的 A 与 B 输入间的混合值。 在给定的示例中,当 Alpha 值为 0 时,将返回 A 的 100% 的值。 当 Alpha 值为 1 时,将返回 B 的 100% 的值。...
JavaScript获取元素的定位参考元素和定位值方法1. offsetParent 获取元素的定位参考元素 element.offsetParent 2. offsetLeft 获取元素到定位参考元素的左边距离 element.offsetLeft 3. offsetTop 获取元素的定位参考元素的上边距离 element.offsetTop &lt;!DOCTYPE htm...
前言本博客使用keil ide和15.3版本的sdk作为环境进行nrf52832芯片开发官方写的软件开发指导书链接:https://infocenter.nordicsemi.com/index.jsp?topic=%2Fug_getting_started%2FUG%2Fcommon%2Fnordic_tools.html&cp=1_0_1官方的开发者社区:https...
本文整理汇总了Python中cv2.cv.CreateImage方法的典型用法代码示例。如果您正苦于以下问题:Python cv.CreateImage方法的具体用法?Python cv.CreateImage怎么用?Python cv.CreateImage使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在模块cv2.cv的用法示例。在下文中一共展...
为什么80%的码农都做不了架构师?>>> ...
LeetCode 898. Bitwise ORs of Subarrays 子数组按位或操作898. Bitwise ORs of Subarrays题目描述示例:解答代码898. Bitwise ORs of Subarrays题目描述We have an array A of non-negative integers.For every (contiguous) subarray ...