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);
    }

 

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