sharding-jdbc源码解析之sql解析

说在前面

本次介绍的是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解析实现的源码解析,仅供参考。

《sharding-jdbc源码解析之sql解析》

关注微信公众号

《sharding-jdbc源码解析之sql解析》

加入技术微信群

《sharding-jdbc源码解析之sql解析》

    原文作者:天河2018
    原文地址: https://www.jianshu.com/p/b5f5235605bc
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞