www1350 / javaweb

http://www1350.github.io/
31 stars 5 forks source link

sharding-jdbc源码解析-sql解析(五) #155

Open www1350 opened 6 years ago

www1350 commented 6 years ago

2121212

SQLParsingEngine

sql分析引擎

会先使用词法分析引擎进行词法分析

@RequiredArgsConstructor
public final class SQLParsingEngine {
    //数据库类型,如mysql
    private final DatabaseType dbType;

    private final String sql;

    private final ShardingRule shardingRule;

    /**
     * Parse SQL.
     * 
     * @return parsed SQL statement
     */
    public SQLStatement parse() {
        //根据sql和数据库类型创建词法分析引擎
        LexerEngine lexerEngine = LexerEngineFactory.newInstance(dbType, sql);
        //读入第一个标记
        lexerEngine.nextToken();
        //使用sql解析工厂创建sql解析器并解析
        return SQLParserFactory.newInstance(dbType, lexerEngine.getCurrentToken().getType(), shardingRule, lexerEngine).parse();
    }
}

SQLParserFactory

sql解析器工厂,负责根据sql第一个标记类型创建出相应的解析器

SQLParser

解析器

diagram

public interface SQLParser {

    /**
     * Parse SQL.
     *
     * @return SQL statement
     */
    SQLStatement parse();
}

以插入为例

插入语句解析器

public abstract class AbstractInsertParser implements SQLParser {

    @Getter(AccessLevel.PROTECTED)
    private final ShardingRule shardingRule;

    @Getter(AccessLevel.PROTECTED)
    private final LexerEngine lexerEngine;

    private final AbstractInsertClauseParserFacade insertClauseParserFacade;

    public AbstractInsertParser(final ShardingRule shardingRule, final LexerEngine lexerEngine, final AbstractInsertClauseParserFacade insertClauseParserFacade) {
        this.shardingRule = shardingRule;
        this.lexerEngine = lexerEngine;
        this.insertClauseParserFacade = insertClauseParserFacade;
    }

    @Override
    public final DMLStatement parse() {
        //读取下一个标记,比如INSERT INTO t_order (user_id, status) VALUES (10, 'INIT')
        //就读取到INTO
        lexerEngine.nextToken();
        //创建InsertStatement
        InsertStatement result = new InsertStatement();
        //读取INTO后面的表名
        insertClauseParserFacade.getInsertIntoClauseParser().parse(result);
        //读取插入的列
        insertClauseParserFacade.getInsertColumnsClauseParser().parse(result);
        //不支持INSERT SELECT
        if (lexerEngine.equalAny(DefaultKeyword.SELECT, Symbol.LEFT_PAREN)) {
            throw new UnsupportedOperationException("Cannot INSERT SELECT");
        }
        //读取VALUES 后面
        insertClauseParserFacade.getInsertValuesClauseParser().parse(result);
         //读取SET 后面
        insertClauseParserFacade.getInsertSetClauseParser().parse(result);
        //处理自增键
        appendGenerateKey(result);
        return result;
    }

    private void appendGenerateKey(final InsertStatement insertStatement) {
        String tableName = insertStatement.getTables().getSingleTableName();
        Optional<String> generateKeyColumn = shardingRule.getGenerateKeyColumn(tableName);
        if (!generateKeyColumn.isPresent() || null != insertStatement.getGeneratedKey()) {
            return;
        } 
        ItemsToken columnsToken = new ItemsToken(insertStatement.getColumnsListLastPosition());
        columnsToken.getItems().add(generateKeyColumn.get());
        insertStatement.getSqlTokens().add(columnsToken);
        insertStatement.getSqlTokens().add(new GeneratedKeyToken(insertStatement.getValuesListLastPosition()));
    }
}

diagram

AbstractInsertClauseParserFacade

门面模式

@RequiredArgsConstructor
@Getter
public abstract class AbstractInsertClauseParserFacade {

    private final InsertIntoClauseParser insertIntoClauseParser;

    private final InsertColumnsClauseParser insertColumnsClauseParser;

    private final InsertValuesClauseParser insertValuesClauseParser;

    private final InsertSetClauseParser insertSetClauseParser;
}

diagram

InsertIntoClauseParser

INTO 部分解析

public void parse(final InsertStatement insertStatement) {
    lexerEngine.unsupportedIfEqual(getUnsupportedKeywordsBeforeInto());
    //一直读取直到结束或者 "INTO"
    lexerEngine.skipUntil(DefaultKeyword.INTO);
    //读取"INTO"下一个标记
    lexerEngine.nextToken();
    //解析表
    tableReferencesClauseParser.parse(insertStatement, true);
    skipBetweenTableAndValues(insertStatement);
}

TableReferencesClauseParser

public final void parse(final SQLStatement sqlStatement, final boolean isSingleTableOnly) {
    do {
        parseTableReference(sqlStatement, isSingleTableOnly);
    } while (lexerEngine.skipIfEqual(Symbol.COMMA));
}

    @Override
    protected void parseTableReference(final SQLStatement sqlStatement, final boolean isSingleTableOnly) {
        parseTableFactor(sqlStatement, isSingleTableOnly);
        //解析PARTITION,Mysql不支持。
        parsePartition();
        //解析使用索引
        parseIndexHint(sqlStatement);
    }

 protected final void parseTableFactor(final SQLStatement sqlStatement, final boolean isSingleTableOnly) {
     //"INTO"下一个标记开始的下标
     //如:INSERT INTO t_order (user_id, status) VALUES (10, 'INIT') 
     //是12
        final int beginPosition = lexerEngine.getCurrentToken().getEndPosition() - lexerEngine.getCurrentToken().getLiterals().length();
     //"INTO"下一个字面量,就是逻辑表名
     //如:INSERT INTO t_order (user_id, status) VALUES (10, 'INIT') 
     //是t_order
        String literals = lexerEngine.getCurrentToken().getLiterals();
     //下一个标记,如(、AS等,
        lexerEngine.nextToken();
     //不能支持`schema.table`
        if (lexerEngine.equalAny(Symbol.DOT)) {
            throw new UnsupportedOperationException("Cannot support SQL for `schema.table`");
        }
     //移除 '`'和 '"'
        String tableName = SQLUtil.getExactlyValue(literals);
     //解析 AS ,拿到别名,并跳到别名下一个标记
        Optional<String> alias = aliasClauseParser.parse();

        if (isSingleTableOnly || shardingRule.tryFindTableRule(tableName).isPresent() || shardingRule.findBindingTableRule(tableName).isPresent()
                || shardingRule.getDataSourceMap().containsKey(shardingRule.getDefaultDataSourceName())) {
            //添加sqlToken (12,t_order)
            sqlStatement.getSqlTokens().add(new TableToken(beginPosition, literals));
            //添加表名和别名
            sqlStatement.getTables().add(new Table(tableName, alias));
        }
     //解析join
        parseJoinTable(sqlStatement);
        if (isSingleTableOnly && !sqlStatement.getTables().isSingleTable()) {
            throw new UnsupportedOperationException("Cannot support Multiple-Table.");
        }

 private void parseIndexHint(final SQLStatement sqlStatement) {
     //USE、IGNORE、FORCE
        if (getLexerEngine().skipIfEqual(DefaultKeyword.USE, MySQLKeyword.IGNORE, MySQLKeyword.FORCE)) {
            //INDEX、KEY、FOR、JOIN、ORDER、GROUP、BY
            getLexerEngine().skipAll(DefaultKeyword.INDEX, DefaultKeyword.KEY, DefaultKeyword.FOR, DefaultKeyword.JOIN, DefaultKeyword.ORDER, DefaultKeyword.GROUP, DefaultKeyword.BY);
            getLexerEngine().skipParentheses(sqlStatement);
        }
    }

AliasClauseParser

public Optional<String> parse() {
    //解析到AS了,就在往下读一个标记
    if (lexerEngine.skipIfEqual(DefaultKeyword.AS)) {
        //读到符号返回不存在
        if (lexerEngine.equalAny(Symbol.values())) {
            return Optional.absent();
        }
        //接下来的字面量去 '`'和 '"'
        String result = SQLUtil.getExactlyValue(lexerEngine.getCurrentToken().getLiterals());
        //往下读
        lexerEngine.nextToken();
        //返回别名
        return Optional.of(result);
    }
    //直接别名的
    if (lexerEngine.equalAny(
            Literals.IDENTIFIER, Literals.CHARS, DefaultKeyword.USER, DefaultKeyword.END, DefaultKeyword.CASE, DefaultKeyword.KEY, DefaultKeyword.INTERVAL, DefaultKeyword.CONSTRAINT)) {
        String result = SQLUtil.getExactlyValue(lexerEngine.getCurrentToken().getLiterals());
        lexerEngine.nextToken();
        //返回别名
        return Optional.of(result);
    }
    return Optional.absent();
}

InsertColumnsClauseParser

列 部分解析

public void parse(final InsertStatement insertStatement) {
    Collection<Column> result = new LinkedList<>();
    // "("开头
    if (lexerEngine.equalAny(Symbol.LEFT_PAREN)) {
        //刚才解析出来的表名
        String tableName = insertStatement.getTables().getSingleTableName();
        //获取该表的分片规则列的列名
        Optional<String> generateKeyColumn = shardingRule.getGenerateKeyColumn(tableName);
        int count = 0;
        //读取INTO 的所有列名
        do {
            lexerEngine.nextToken();
            String columnName = SQLUtil.getExactlyValue(lexerEngine.getCurrentToken().getLiterals());
            result.add(new Column(columnName, tableName));
            lexerEngine.nextToken();
            if (generateKeyColumn.isPresent() && generateKeyColumn.get().equalsIgnoreCase(columnName)) {
                //记下需要自增的列的位置
                insertStatement.setGenerateKeyColumnIndex(count);
            }
            count++;
        } while (!lexerEngine.equalAny(Symbol.RIGHT_PAREN) && !lexerEngine.equalAny(Assist.END));      
//记录最后一列结束位置
        insertStatement.setColumnsListLastPosition(lexerEngine.getCurrentToken().getEndPosition() - lexerEngine.getCurrentToken().getLiterals().length());
        //跳过")"
        lexerEngine.nextToken();
    }
    //设置列名
    insertStatement.getColumns().addAll(result);
}

InsertValuesClauseParser

public void parse(final InsertStatement insertStatement) {
    Collection<Keyword> valueKeywords = new LinkedList<>();
    //VALUES
    valueKeywords.add(DefaultKeyword.VALUES);
    //mysql是VALUE
    valueKeywords.addAll(Arrays.asList(getSynonymousKeywordsForValues()));
    //读到VALUES或VALUE,接着读下一个
    if (lexerEngine.skipIfEqual(valueKeywords.toArray(new Keyword[valueKeywords.size()]))) {
        //记录VALUES或VALUE后面开始的位置
        insertStatement.setAfterValuesPosition(lexerEngine.getCurrentToken().getEndPosition() - lexerEngine.getCurrentToken().getLiterals().length());
        //VALUES或VALUE的值和表名组成Condition
        parseValues(insertStatement);
        //如果是","表示批量插入的写法
        if (lexerEngine.equalAny(Symbol.COMMA)) {
            parseMultipleValues(insertStatement);
        }
    }
}

private void parseValues(final InsertStatement insertStatement) {
    //跳过"("
        lexerEngine.accept(Symbol.LEFT_PAREN);
        List<SQLExpression> sqlExpressions = new LinkedList<>();
        do {
            //表达式,就是每一个值,逗号隔开
            sqlExpressions.add(expressionClauseParser.parse(insertStatement));
        } while (lexerEngine.skipIfEqual(Symbol.COMMA));
  //记录结束位置      
  insertStatement.setValuesListLastPosition(lexerEngine.getCurrentToken().getEndPosition() - lexerEngine.getCurrentToken().getLiterals().length());
        int count = 0;
    //列名和值组装成条件Condition
        for (Column each : insertStatement.getColumns()) {
            SQLExpression sqlExpression = sqlExpressions.get(count);
            insertStatement.getConditions().add(new Condition(each, sqlExpression), shardingRule);
            if (insertStatement.getGenerateKeyColumnIndex() == count) {
                insertStatement.setGeneratedKey(createGeneratedKey(each, sqlExpression));
            }
            count++;
        }
    //跳过")"
        lexerEngine.accept(Symbol.RIGHT_PAREN);
    }