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

相關文章
相關標籤/搜索