ShardingJdbc2.X學習總結系列(十三):源碼解析—SQL解析之Insert語句的values解析

這一篇我們主要具體看一下Insert語句的values解析

public void parse(final InsertStatement insertStatement) {
        Collection<Keyword> valueKeywords = new LinkedList<>();
        valueKeywords.add(DefaultKeyword.VALUES);
        valueKeywords.addAll(Arrays.asList(getSynonymousKeywordsForValues()));
        if (lexerEngine.skipIfEqual(valueKeywords.toArray(new Keyword[valueKeywords.size()]))) {
            insertStatement.setAfterValuesPosition(lexerEngine.getCurrentToken().getEndPosition() - lexerEngine.getCurrentToken().getLiterals().length());
            //解析values
            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(basicExpressionParser.parse(insertStatement));
        } while (lexerEngine.skipIfEqual(Symbol.COMMA));
        insertStatement.setValuesListLastPosition(lexerEngine.getCurrentToken().getEndPosition() - lexerEngine.getCurrentToken().getLiterals().length());
        int count = 0;
        //循環所有的字段,組裝字段與表達式的關係
        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);
    }

看一下解析條件表達式:這裏主要是解析成SQLExpression,我們看一下這個接口的實現關係

那麼這裏是如何對應解析關係和SQLExpression的呢

private SQLExpression getExpression(final String literals, final SQLStatement sqlStatement) {
        //問號解析成 佔位符表達式,存儲的是參數的下標
        if (lexerEngine.equalAny(Symbol.QUESTION)) {
            sqlStatement.increaseParametersIndex();
            return new SQLPlaceholderExpression(sqlStatement.getParametersIndex() - 1);
        }
        //字符解析成 文本表達式,存儲字符的值
        if (lexerEngine.equalAny(Literals.CHARS)) {
            return new SQLTextExpression(literals);
        }
        //整型數值解析成 數字表達式,存儲數字的值
        if (lexerEngine.equalAny(Literals.INT)) {
            return new SQLNumberExpression(NumberUtil.getExactlyNumber(literals, 10));
        }
        //浮點型數值解析成 數字表達式,存儲數字的值
        if (lexerEngine.equalAny(Literals.FLOAT)) {
            return new SQLNumberExpression(Double.parseDouble(literals));
        }
        //十六進制數值解析成 數字表達式,存儲數字的值
        if (lexerEngine.equalAny(Literals.HEX)) {
            return new SQLNumberExpression(NumberUtil.getExactlyNumber(literals, 16));
        }
        //標識符 解析成標識符表達式,存儲當前標識符的值
        if (lexerEngine.equalAny(Literals.IDENTIFIER)) {
            return new SQLIdentifierExpression(SQLUtil.getExactlyValue(literals));
        }
        //其他 默認解析成忽略的表達式
        return new SQLIgnoreExpression(literals);
    }

解析成表達式後,我們看一下字段跟表達式的關係建立

insertStatement.getConditions().add(new Condition(each, sqlExpression), shardingRule);

我們首先看一下這個Condition的字段以及構造方法

column:字段信息
operator:條件的類型(EQUAL,BETWEEN,IN)
positionValueMap:這裏存儲的是需要的參數下標與值(數字或者文字)的關係
positionIndexMap:這裏存儲的是需要的參數下標與入參的下標的關係

舉例:INSERT INTO user(name) VALUES ("曉明")          column:user     operator:EQUAL   positionValueMap:(0,"曉明")

INSERT INTO user(name) VALUES (?)          column:user     operator:EQUAL   positionIndexMap:(0,0)

INSERT INTO user(name,sex) VALUES (“曉明”,?)   

column:user        operator:EQUAL            positionIndexMap:(0,0)              positionValueMap:(0,"曉明")

如果是between ? and ? 這種形式的  解析成positionIndexMap:(0,0) (1,1),positionValueMap:(0,"曉明")(1,"曉紅")

第一個值代表的是between and中問號的下標,第二個值是當前執行語句的參數的下標。

public void add(final Condition condition, final ShardingRule shardingRule) {
        // TODO self-join has problem, table name maybe use alias
        if (shardingRule.isShardingColumn(condition.getColumn())) {
            conditions.put(condition.getColumn(), condition);
        }
    }

最終我們發現,在insert,values解析的時候,只有分庫分表的字段才被保留對應的關係,其他字段的對應關係是沒有要的。

單條記錄解析完成之後,我們看一下如果同時插入多條數據怎麼辦?

private void parseMultipleValues(final InsertStatement insertStatement) {
        //把第一條添加的數據條件放到MultipleConditions中
        insertStatement.getMultipleConditions().add(new Conditions(insertStatement.getConditions()));
        //把第一條添加的數據放到MultipleInsertValuesToken的values中
        MultipleInsertValuesToken valuesToken = new MultipleInsertValuesToken(insertStatement.getAfterValuesPosition());
        valuesToken.getValues().add(
                lexerEngine.getInput().substring(insertStatement.getAfterValuesPosition(), lexerEngine.getCurrentToken().getEndPosition() - Symbol.COMMA.getLiterals().length()));
        //遍歷後續的插入值
        while (lexerEngine.skipIfEqual(Symbol.COMMA)) {
            int beginPosition = lexerEngine.getCurrentToken().getEndPosition() - lexerEngine.getCurrentToken().getLiterals().length();
            //解析插入值
            parseValues(insertStatement);
            //把當前的這條插入條件添加到MultipleConditions
            insertStatement.getMultipleConditions().add(new Conditions(insertStatement.getConditions()));
            int endPosition = lexerEngine.equalAny(Symbol.COMMA)
                    ? lexerEngine.getCurrentToken().getEndPosition() - Symbol.COMMA.getLiterals().length() : lexerEngine.getCurrentToken().getEndPosition();
//把當前這條添加的數據放到MultipleInsertValuesToken的values中valuesToken.getValues().add(lexerEngine.getInput().substring(beginPosition, endPosition));
        }
        //把MultipleInsertValuesToken添加到sqlToken中
        insertStatement.getSqlTokens().add(valuesToken);
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章