说在前面
本次介绍的是sharding-jdbc的源码解析部分的sql解析,这一部分主要是把逻辑sql语句装在到sharding-jdbc的数据模型中,为后期的sql路由处理做基础工作。
sql解析源码解析
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解析器
/**
* 创建Select语句解析器.
*
* @param sqlParser SQL解析器
* @return Select语句解析器
*/
public static AbstractSelectParser newInstance(final AbstractSQLParser sqlParser) {
if (sqlParser instanceof MySQLParser) {
return new MySQLSelectParser(sqlParser);
}
进入到parse方法
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;
}
进入到这个方法
parseDistinct();
从这个方法看出是不支持distinct关键字的
private void parseDistinct() {
sqlParser.skipAll(DefaultKeyword.ALL);
Collection 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 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@ToStringpublic 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 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 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 items = new LinkedList<>();//选择项对象
private final List groupByItems = new LinkedList<>();//排序项对象
private final List orderByItems = new LinkedList<>();
/** * 分页对象. * * @author zhangliang * @author caohao */@RequiredArgsConstructor@Getter@Setter@ToStringpublic final class Limit { private final boolean rowCountRewriteFlag; private LimitValue offset;
/** * 排序项. * * @author zhangliang */@Getter@Setter@EqualsAndHashCode@ToStringpublic final class OrderItem { private final Optional owner; private final Optional name; private final OrderType type; private int index = -1; private Optional alias;
/** * 排序类型. * * @author zhangliang */public enum OrderType { ASC, DESC}
/** * 选择项. * * @author zhangliang */@RequiredArgsConstructor@Getter@ToStringpublic final class CommonSelectItem implements SelectItem {// 表达式 private final String expression;// 别名 private final Optional alias;}
** * 聚合选择项. * * @author zhangliang */@RequiredArgsConstructor@Getter@EqualsAndHashCode@ToStringpublic final class AggregationSelectItem implements SelectItem {// 聚合选择项内容 private final AggregationType type; private final String innerExpression; private final Optional alias; private final List 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 */@ToStringpublic final class Tables { private final List tables = new ArrayList<>();
/** * 条件对象集合. * * @author zhangliang */@RequiredArgsConstructor@ToStringpublic final class Conditions { private final Map conditions = new LinkedHashMap<>();
/** * 表标记对象. * * @author zhangliang */@RequiredArgsConstructor@Getter@ToStringpublic final class TableToken implements SQLToken { private final int beginPosition; private final String originalLiterals;
/** * 排序类型. * * @author zhangliang */public enum OrderType { ASC, DESC}
说到最后
以上sql解析实现的源码解析,仅供参考。
关注微信公众号
加入技术微信群