sharding-jdbc源码解析之sql解析

说在前面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解析实现的源码解析,仅供参考。

相关文章
相关标签/搜索