说在前面mysql
本文转自“天河聊技术”微信公众号sql
本次介绍的是sharding-jdbc的源码解析部分的sql解析,这一部分主要是把逻辑sql语句装在到sharding-jdbc的数据模型中,为后期的sql路由处理作基础工做。数据库
sql解析源码解析express
sharding-jdbc针对不一样的数据库有的不一样的具体的解析器的实现,本次咱们主要针对mysql为主来跟踪下源码怎么实现的sql解析逻辑,首先找到sql解析引擎类设计模式
com.dangdang.ddframe.rdb.sharding.parsing.SQLParsingEngine这个类,主要方法是这个微信
/** * 解析SQL. * * @return SQL语句对象 */ public SQLStatement parse() {//业务方法 AbstractSQLParser sqlParser = getSQLParser();//获取到对应的数据库parser对象 sqlParser.skipIfEqual(Symbol.SEMI);//跳过; if (sqlParser.equalAny(DefaultKeyword.WITH)) { skipWith(sqlParser); } if (sqlParser.equalAny(DefaultKeyword.SELECT)) {//这里是工厂方法设计模式实现 return SelectParserFactory.newInstance(sqlParser).parse();
进入到这个方法 SelectParserFactory.newInstance(sqlParser)内,建立select语句的sql解析器app
/** * 建立Select语句解析器. * * @param sqlParser SQL解析器 * @return Select语句解析器 */ public static AbstractSelectParser newInstance(final AbstractSQLParser sqlParser) { if (sqlParser instanceof MySQLParser) { return new MySQLSelectParser(sqlParser); }
进入到parse方法less
SelectParserFactory.newInstance(sqlParser).parse();
select解析器中的主要逻辑是这个方法 @Override public final SelectStatement parse() {//select语句解析方法 sqlParser.getLexer().nextToken(); parseDistinct(); parseBeforeSelectList(); parseSelectList(); parseFrom(); parseWhere(); customizedBetweenWhereAndGroupBy(); parseGroupBy(); customizedBetweenGroupByAndOrderBy(); parseOrderBy(); customizedSelect(); processUnsupportedTokens(); // TODO move to rewrite appendDerivedColumns();//解析聚合函数 appendDerivedOrderBy(); return selectStatement; }
进入到这个方法ide
parseDistinct();
从这个方法看出是不支持distinct关键字的函数
private void parseDistinct() { sqlParser.skipAll(DefaultKeyword.ALL); Collection<Keyword> distinctKeywords = Lists.newLinkedList(getCustomizedDistinctKeywords()); distinctKeywords.add(DefaultKeyword.DISTINCT);//不支持distinct关键字 if (getSqlParser().equalAny(distinctKeywords.toArray(new Keyword[distinctKeywords.size()]))) { throw new SQLParsingUnsupportedException(getSqlParser().getLexer().getCurrentToken().getType()); } }
进入到这个方法
parseSelectList();
private void parseSelectList() { do { // 解析select后面的字段 parseSelectItem(); } while (sqlParser.skipIfEqual(Symbol.COMMA)); selectStatement.setSelectListLastPosition(sqlParser.getLexer().getCurrentToken().getEndPosition() - sqlParser.getLexer().getCurrentToken().getLiterals().length()); }
进入到这个方法
parseSelectItem();
private void parseSelectItem() { sqlParser.skipIfEqual(getSkipKeywordsBeforeSelectItem()); // 是不是rownumber的列 if (isRowNumberSelectItem()) { // mysql不支持rownumber selectStatement.getItems().add(parseRowNumberSelectItem()); return; }
String literals = sqlParser.getLexer().getCurrentToken().getLiterals(); // 去掉select后的特殊字符,是否查询表的全部字段 if (Symbol.STAR.getLiterals().equals(SQLUtil.getExactlyValue(literals))) { selectStatement.getItems().add(parseStarSelectItem()); return; }
进入到parseStarSelectItem方法
// 解析表所有列 private SelectItem parseStarSelectItem() { if (!containSubquery) { containStarForOutQuery = true; } sqlParser.getLexer().nextToken(); selectStatement.setContainStar(true); return new CommonSelectItem(Symbol.STAR.getLiterals(), sqlParser.parseAlias()); }
进入到这个parseAlias方法
public Optional<String> parseAlias() { // 别名以前必需要有as关键字的,不然解析不到 if (skipIfEqual(DefaultKeyword.AS)) { if (equalAny(Symbol.values())) { return Optional.absent(); } String result = SQLUtil.getExactlyValue(getLexer().getCurrentToken().getLiterals()); getLexer().nextToken(); return Optional.of(result); }
这里解析别名是解析as关键字的,解析不到这个关键字会报错
往上返回到parseSelectItem这个方法
// 解析聚合函数 if (isAggregationSelectItem()) { selectStatement.getItems().add(parseAggregationSelectItem(literals)); return; }
聚合选择项类型
public enum AggregationType { MAX, MIN, SUM, COUNT, AVG }
进入到
parseAggregationSelectItem()方法内
private SelectItem parseAggregationSelectItem(final String literals) { // sqlParser.skipParentheses()解析聚合函数后面的小括号内的词法标记 return new AggregationSelectItem(AggregationType.valueOf(literals.toUpperCase()), sqlParser.skipParentheses(), sqlParser.parseAlias()); }
返回到parseSelectItem方法
书否包含. if (sqlParser.equalAny(Symbol.DOT)) { selectStatement.getSqlTokens().add(new TableToken(position, value)); }
/** * SQL语句对象抽象类. * * @author zhangliang */ @RequiredArgsConstructor @Getter @ToString public abstract class AbstractSQLStatement implements SQLStatement { // sql类型 private final SQLType type; // 表集合 private final Tables tables = new Tables(); // 条件集合 private final Conditions conditions = new Conditions(); // sql标记对象集合 private final List<SQLToken> sqlTokens = new LinkedList<>();
if (hasAlias(expression, lastToken)) { // 解析有别名的select选择项 selectStatement.getItems().add(parseSelectItemWithAlias(expression, lastToken)); return; } selectStatement.getItems().add(new CommonSelectItem(SQLUtil.getExactlyValue(expression.toString()), sqlParser.parseAlias()));
往上返回到这个方法
com.dangdang.ddframe.rdb.sharding.parsing.parser.statement.dql.select.AbstractSelectParser#parse
// 解析from后的语句 parseFrom();
进入到这个方法
private void parseFrom() { if (getSqlParser().equalAny(DefaultKeyword.INTO)) {//不支持select into throw new SQLParsingUnsupportedException(DefaultKeyword.INTO); } if (sqlParser.skipIfEqual(DefaultKeyword.FROM)) { parseTable();//解析表 } }
从这里能够看出是不支持select...into这种sql语句写法
进入到这个方法
com.dangdang.ddframe.rdb.sharding.parsing.parser.statement.dql.select.AbstractSelectParser#parseTable
private void parseTable() { // 解析(里面的内容 if (sqlParser.skipIfEqual(Symbol.LEFT_PAREN)) { if (!selectStatement.getTables().isEmpty()) {//不支持子查询 throw new UnsupportedOperationException("Cannot support subquery for nested tables."); } containSubquery = true; selectStatement.setContainStar(false); // 跳过嵌套的无用的小括号 sqlParser.skipUselessParentheses(); parse(); sqlParser.skipUselessParentheses(); if (getSqlParser().equalAny(DefaultKeyword.WHERE, Assist.END)) { return; } } //解析表 customizedParseTableFactor(); // 解析关联的表 parseJoinTable(); }
解析关联的表
protected void parseJoinTable() { if (sqlParser.skipJoin()) { parseTable(); if (sqlParser.skipIfEqual(DefaultKeyword.ON)) { do { // 解析table的条件 parseTableCondition(sqlParser.getLexer().getCurrentToken().getEndPosition()); sqlParser.accept(Symbol.EQ); parseTableCondition(sqlParser.getLexer().getCurrentToken().getEndPosition() - sqlParser.getLexer().getCurrentToken().getLiterals().length()); } while (sqlParser.skipIfEqual(DefaultKeyword.AND)); } else if (sqlParser.skipIfEqual(DefaultKeyword.USING)) { sqlParser.skipParentheses(); } parseJoinTable(); } }
回到这个方法
com.dangdang.ddframe.rdb.sharding.parsing.parser.statement.dql.select.AbstractSelectParser#parse
// 解析where后的语句 parseWhere();
/** * 解析查询条件. * * @param sqlStatement SQL语句对象 */ public final void parseWhere(final SQLStatement sqlStatement) { // 解析别名 parseAlias(); if (skipIfEqual(DefaultKeyword.WHERE)) { // 解析where后的条件表达式 parseConditions(sqlStatement); } }
private void parseConditions(final SQLStatement sqlStatement) { do { parseComparisonCondition(sqlStatement); } while (skipIfEqual(DefaultKeyword.AND));//解析where后的and条件 if (equalAny(DefaultKeyword.OR)) {//不支持or throw new SQLParsingUnsupportedException(getLexer().getCurrentToken().getType()); } }
从这里能够看出是不支持or操做的
进入解析比较表达式的这个方法
// TODO 解析组合expr public final void parseComparisonCondition(final SQLStatement sqlStatement) { skipIfEqual(Symbol.LEFT_PAREN); // 解析表达式 SQLExpression left = parseExpression(sqlStatement); if (equalAny(Symbol.EQ)) {//解析=表达式 parseEqualCondition(sqlStatement, left); skipIfEqual(Symbol.RIGHT_PAREN); return; } if (equalAny(DefaultKeyword.IN)) {//解析in表达式 parseInCondition(sqlStatement, left); skipIfEqual(Symbol.RIGHT_PAREN); return; } // 解析between表达式 if (equalAny(DefaultKeyword.BETWEEN)) { parseBetweenCondition(sqlStatement, left); skipIfEqual(Symbol.RIGHT_PAREN); return; }
返回到这个方法的解析group by的这一行代码
@Override public final SelectStatement parse() {//select语句解析方法 sqlParser.getLexer().nextToken(); // 解析distinct关键字 parseDistinct(); parseBeforeSelectList(); // 解析select选择项 parseSelectList(); // 解析from后的语句 parseFrom(); // 解析where后的语句 parseWhere(); customizedBetweenWhereAndGroupBy(); // 解析group by语句 parseGroupBy(); customizedBetweenGroupByAndOrderBy(); parseOrderBy(); customizedSelect(); processUnsupportedTokens(); // TODO move to rewrite appendDerivedColumns();//解析聚合函数 appendDerivedOrderBy(); return selectStatement; }
protected void parseGroupBy() {//解析group by if (sqlParser.skipIfEqual(DefaultKeyword.GROUP)) { sqlParser.accept(DefaultKeyword.BY); while (true) { // 解析group by项 addGroupByItem(sqlParser.parseExpression(selectStatement)); if (!sqlParser.equalAny(Symbol.COMMA)) { break; } sqlParser.getLexer().nextToken(); } while (sqlParser.equalAny(DefaultKeyword.WITH) || sqlParser.getLexer().getCurrentToken().getLiterals().equalsIgnoreCase("ROLLUP")) { sqlParser.getLexer().nextToken(); } if (sqlParser.skipIfEqual(DefaultKeyword.HAVING)) {//不支持having throw new UnsupportedOperationException("Cannot support Having"); } selectStatement.setGroupByLastPosition(sqlParser.getLexer().getCurrentToken().getEndPosition() - getSqlParser().getLexer().getCurrentToken().getLiterals().length()); } else if (sqlParser.skipIfEqual(DefaultKeyword.HAVING)) { throw new UnsupportedOperationException("Cannot support Having"); } }
从上面的这个方法实现能够看出是不支持having这种操做的
进入到组装排序项的这个方法
protected final void addGroupByItem(final SQLExpression sqlExpression) { // 默认升序排序 OrderType orderByType = OrderType.ASC; if (sqlParser.equalAny(DefaultKeyword.ASC)) { sqlParser.getLexer().nextToken(); } else if (sqlParser.skipIfEqual(DefaultKeyword.DESC)) { orderByType = OrderType.DESC; }
能够看出是默认升序排序的
返回到这个方法的解析order by的这行代码
@Override public final SelectStatement parse() {//select语句解析方法 sqlParser.getLexer().nextToken(); // 解析distinct关键字 parseDistinct(); parseBeforeSelectList(); // 解析select选择项 parseSelectList(); // 解析from后的语句 parseFrom(); // 解析where后的语句 parseWhere(); customizedBetweenWhereAndGroupBy(); // 解析group by语句 parseGroupBy(); customizedBetweenGroupByAndOrderBy(); // 解析order by语句 parseOrderBy(); customizedSelect(); processUnsupportedTokens(); // TODO move to rewrite appendDerivedColumns();//解析聚合函数 appendDerivedOrderBy(); return selectStatement; }
protected final void parseOrderBy() {//解析order by if (!sqlParser.skipIfEqual(DefaultKeyword.ORDER)) { return; } List<OrderItem> result = new LinkedList<>(); sqlParser.skipIfEqual(DefaultKeyword.SIBLINGS); sqlParser.accept(DefaultKeyword.BY); do { // 解析查询排序选择项 OrderItem orderItem = parseSelectOrderByItem(); if (!containSubquery || containStarForOutQuery) { result.add(orderItem); } } while (sqlParser.skipIfEqual(Symbol.COMMA)); selectStatement.getOrderByItems().addAll(result); }
private OrderItem parseSelectOrderByItem() { SQLExpression sqlExpression = sqlParser.parseExpression(selectStatement); OrderType orderByType = OrderType.ASC;//默认升序 if (sqlParser.skipIfEqual(DefaultKeyword.ASC)) { orderByType = OrderType.ASC; } else if (sqlParser.skipIfEqual(DefaultKeyword.DESC)) { orderByType = OrderType.DESC; }
默认升序
返回到这个方法
@Override public final SelectStatement parse() {//select语句解析方法 sqlParser.getLexer().nextToken(); // 解析distinct关键字 parseDistinct(); parseBeforeSelectList(); // 解析select选择项 parseSelectList(); // 解析from后的语句 parseFrom(); // 解析where后的语句 parseWhere(); customizedBetweenWhereAndGroupBy(); // 解析group by语句 parseGroupBy(); customizedBetweenGroupByAndOrderBy(); // 解析order by语句 parseOrderBy(); customizedSelect(); // 解析不支持的操做 processUnsupportedTokens(); // TODO move to rewrite appendDerivedColumns();//解析聚合函数 appendDerivedOrderBy(); return selectStatement; }
processUnsupportedTokens();这行代码,解析不支持的操做
private void processUnsupportedTokens() {//不支持union if (sqlParser.equalAny(DefaultKeyword.UNION, DefaultKeyword.EXCEPT, DefaultKeyword.INTERSECT, DefaultKeyword.MINUS)) { throw new SQLParsingUnsupportedException(sqlParser.getLexer().getCurrentToken().getType()); } }
总结下sql解析用到的数据模型
/** * 支持的数据库类型. * * @author zhangliang */ public enum DatabaseType { H2("H2"), MySQL("MySQL"), Oracle("Oracle"), SQLServer("Microsoft SQL Server"), PostgreSQL("PostgreSQL");
/** * Select SQL语句对象. * * @author zhangliang */ @Getter @Setter @ToString(callSuper = true) public final class SelectStatement extends DQLStatement { private boolean containStar;//是否查询全部字段 select * private int selectListLastPosition; private int groupByLastPosition; private final List<SelectItem> items = new LinkedList<>();//选择项对象 private final List<OrderItem> groupByItems = new LinkedList<>();//排序项对象 private final List<OrderItem> orderByItems = new LinkedList<>();
/** * 分页对象. * * @author zhangliang * @author caohao */ @RequiredArgsConstructor @Getter @Setter @ToString public final class Limit { private final boolean rowCountRewriteFlag; private LimitValue offset;
/** * 排序项. * * @author zhangliang */ @Getter @Setter @EqualsAndHashCode @ToString public final class OrderItem { private final Optional<String> owner; private final Optional<String> name; private final OrderType type; private int index = -1; private Optional<String> alias;
/** * 排序类型. * * @author zhangliang */ public enum OrderType { ASC, DESC }
/** * 选择项. * * @author zhangliang */ @RequiredArgsConstructor @Getter @ToString public final class CommonSelectItem implements SelectItem { // 表达式 private final String expression; // 别名 private final Optional<String> alias; }
** * 聚合选择项. * * @author zhangliang */ @RequiredArgsConstructor @Getter @EqualsAndHashCode @ToString public final class AggregationSelectItem implements SelectItem { // 聚合选择项内容 private final AggregationType type; private final String innerExpression; private final Optional<String> alias; private final List<AggregationSelectItem> derivedAggregationSelectItems = new ArrayList<>(2); @Setter private int index = -1;
/** * 聚合函数类型. * * @author zhangliang */ public enum AggregationType { MAX, MIN, SUM, COUNT, AVG }
/** * SQL类型. * * @author zhangliang */ public enum SQLType { DQL, DML, DDL }
/** * 表集合对象. * * @author zhangliang */ @ToString public final class Tables { private final List<Table> tables = new ArrayList<>();
/** * 条件对象集合. * * @author zhangliang */ @RequiredArgsConstructor @ToString public final class Conditions { private final Map<Column, Condition> conditions = new LinkedHashMap<>();
/** * 表标记对象. * * @author zhangliang */ @RequiredArgsConstructor @Getter @ToString public final class TableToken implements SQLToken { private final int beginPosition; private final String originalLiterals;
/** * 排序类型. * * @author zhangliang */ public enum OrderType { ASC, DESC }
说到最后
以上sql解析实现的源码解析,仅供参考。