說在前面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解析實現的源碼解析,僅供參考。