5. 开始解析insert语句,AbstractInsertParser#parse,执行nextToken获取到下一个字符段INTO,
public final DMLStatement parse() {
lexerEngine.nextToken();
InsertStatement result = new InsertStatement();
insertClauseParserFacade.getInsertIntoClauseParser().parse(result);
insertClauseParserFacade.getInsertColumnsClauseParser().parse(result, shardingMetaData);
if (lexerEngine.equalAny(DefaultKeyword.SELECT, Symbol.LEFT_PAREN)) {
throw new UnsupportedOperationException("Cannot INSERT SELECT");
}
insertClauseParserFacade.getInsertValuesClauseParser().parse(result, shardingMetaData);
insertClauseParserFacade.getInsertSetClauseParser().parse(result);
processGeneratedKey(result);
return result;
}
InsertIntoClauseParser#parse,校验不支持的关键词,如果该字段不是INTO关键词或者是Assist.END,则跳过获取下一个字符段
public void parse(final InsertStatement insertStatement) {
lexerEngine.unsupportedIfEqual(getUnsupportedKeywordsBeforeInto());
lexerEngine.skipUntil(DefaultKeyword.INTO);
lexerEngine.nextToken();
tableReferencesClauseParser.parse(insertStatement, true);
skipBetweenTableAndValues(insertStatement);
}
继续获取下移字符段,表名,TableReferencesClauseParser以及子类MySQLTableReferencesClauseParser
public final void parse(final SQLStatement sqlStatement, final boolean isSingleTableOnly) {
do {
parseTableReference(sqlStatement, isSingleTableOnly);
} while (lexerEngine.skipIfEqual(Symbol.COMMA));
}
protected void parseTableReference(final SQLStatement sqlStatement, final boolean isSingleTableOnly) {
parseTableFactor(sqlStatement, isSingleTableOnly);
parsePartition();
parseIndexHint(sqlStatement);
}
获取表名以及下标解析出正确的表名,解析别名,保存表名以及它的相关标识TableToken,解析强制走索引标识以及JOIN.最后解析分区字符段和索引标识,最后跳过一些mysql的分区关键词,完成解析。
protected final void parseTableFactor(final SQLStatement sqlStatement, final boolean isSingleTableOnly) {
final int beginPosition = lexerEngine.getCurrentToken().getEndPosition() - lexerEngine.getCurrentToken().getLiterals().length();
String literals = lexerEngine.getCurrentToken().getLiterals();
int skippedSchemaNameLength = 0;
lexerEngine.nextToken();
if (lexerEngine.skipIfEqual(Symbol.DOT)) {
skippedSchemaNameLength = literals.length() + Symbol.DOT.getLiterals().length();
literals = lexerEngine.getCurrentToken().getLiterals();
}
String tableName = SQLUtil.getExactlyValue(literals);
if (Strings.isNullOrEmpty(tableName)) {
return;
}
Optional<String> alias = aliasExpressionParser.parseTableAlias();
if (isSingleTableOnly || shardingRule.tryFindTableRuleByLogicTable(tableName).isPresent() || shardingRule.findBindingTableRule(tableName).isPresent()
|| shardingRule.getShardingDataSourceNames().getDataSourceNames().contains(shardingRule.getShardingDataSourceNames().getDefaultDataSourceName())) {
sqlStatement.getSqlTokens().add(new TableToken(beginPosition, skippedSchemaNameLength, literals));
sqlStatement.getTables().add(new Table(tableName, alias));
}
parseForceIndex(tableName, sqlStatement);
parseJoinTable(sqlStatement);
if (isSingleTableOnly && !sqlStatement.getTables().isSingleTable()) {
throw new UnsupportedOperationException("Cannot support Multiple-Table.");
}
}
6. 解析字段InsertColumnsClauseParser,获取表名以及分表字段,解析具体的字段以及逗号标识,碰到相应的分表字段则记录相应的下标,记录最后一个字段的下标,最后记录字段列的相关数据。
public void parse(final InsertStatement insertStatement, final ShardingMetaData shardingMetaData) {
Collection<Column> result = new LinkedList<>();
String tableName = insertStatement.getTables().getSingleTableName();
Optional<Column> generateKeyColumn = shardingRule.getGenerateKeyColumn(tableName);
int count = 0;
if (lexerEngine.equalAny(Symbol.LEFT_PAREN)) {
do {
lexerEngine.nextToken();
String columnName = SQLUtil.getExactlyValue(lexerEngine.getCurrentToken().getLiterals());
result.add(new Column(columnName, tableName));
lexerEngine.nextToken();
if (generateKeyColumn.isPresent() && generateKeyColumn.get().getName().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();
} else {
List<String> columnNames = shardingMetaData.getTableMetaDataMap().get(tableName).getAllColumnNames();
int beginPosition = lexerEngine.getCurrentToken().getEndPosition() - lexerEngine.getCurrentToken().getLiterals().length() - 1;
insertStatement.getSqlTokens().add(new InsertColumnToken(beginPosition, "("));
ItemsToken columnsToken = new ItemsToken(beginPosition);
columnsToken.setFirstOfItemsSpecial(true);
for (String columnName : columnNames) {
result.add(new Column(columnName, tableName));
if (generateKeyColumn.isPresent() && generateKeyColumn.get().getName().equalsIgnoreCase(columnName)) {
insertStatement.setGenerateKeyColumnIndex(count);
}
columnsToken.getItems().add(columnName);
count++;
}
insertStatement.getSqlTokens().add(columnsToken);
insertStatement.getSqlTokens().add(new InsertColumnToken(beginPosition, ")"));
insertStatement.setColumnsListLastPosition(beginPosition);
}
insertStatement.getColumns().addAll(result);
}
7. 解析值字符段VALUES,InsertValuesClauseParser#parse,mysql也支持value关键词
public void parse(final InsertStatement insertStatement, final ShardingMetaData shardingMetaData) {
Collection<Keyword> valueKeywords = new LinkedList<>();
valueKeywords.add(DefaultKeyword.VALUES);
valueKeywords.addAll(Arrays.asList(getSynonymousKeywordsForValues()));
if (lexerEngine.skipIfEqual(valueKeywords.toArray(new Keyword[valueKeywords.size()]))) {
parseValues(insertStatement);
}
}
解析()内的字符,添加值token标识,在BasicExpressionParser中解析值表达式?等等,循环判断英文逗号,获取所有的值,保存SQLExpression表达式,当分表列需要自动生成时,需要把该列数据清除掉removeGenerateKeyColumn,保存分库分表列,单独记录分表列,记录需要设置的参数数量,保存值字符段为InsertValue,最后把所有解析后的数据保存在InsertStatement,最后InsertSetClauseParser解析mysql的SET关键词,处理分表字段的相关逻辑,sql解析完毕。把结果保存在以该sql为key的缓存中
private void parseValues(final InsertStatement insertStatement) {
int beginPosition = lexerEngine.getCurrentToken().getEndPosition() - lexerEngine.getCurrentToken().getLiterals().length();
int endPosition;
insertStatement.getSqlTokens().add(new InsertValuesToken(beginPosition, insertStatement.getTables().getSingleTableName()));
do {
beginPosition = lexerEngine.getCurrentToken().getEndPosition() - lexerEngine.getCurrentToken().getLiterals().length();
lexerEngine.accept(Symbol.LEFT_PAREN);
List<SQLExpression> sqlExpressions = new LinkedList<>();
int columnsCount = 0;
do {
sqlExpressions.add(basicExpressionParser.parse(insertStatement));
skipsDoubleColon();
columnsCount++;
} while (lexerEngine.skipIfEqual(Symbol.COMMA));
removeGenerateKeyColumn(insertStatement, columnsCount);
columnsCount = 0;
int parametersCount = 0;
AndCondition andCondition = new AndCondition();
for (Column each : insertStatement.getColumns()) {
SQLExpression sqlExpression = sqlExpressions.get(columnsCount);
if (shardingRule.isShardingColumn(each)) {
andCondition.getConditions().add(new Condition(each, sqlExpression));
}
if (insertStatement.getGenerateKeyColumnIndex() == columnsCount) {
insertStatement.getGeneratedKeyConditions().add(createGeneratedKeyCondition(each, sqlExpression));
}
columnsCount++;
if (sqlExpression instanceof SQLPlaceholderExpression) {
parametersCount++;
}
}
lexerEngine.accept(Symbol.RIGHT_PAREN);
endPosition = lexerEngine.getCurrentToken().getEndPosition() - lexerEngine.getCurrentToken().getLiterals().length();
insertStatement.getInsertValues().getInsertValues().add(new InsertValue(lexerEngine.getInput().substring(beginPosition, endPosition), parametersCount));
insertStatement.getConditions().getOrCondition().getAndConditions().add(andCondition);
} while (lexerEngine.skipIfEqual(Symbol.COMMA));
insertStatement.setInsertValuesListLastPosition(endPosition);
}
8. 在ParsingSQLRouter中进行路由设置,获取分表列GeneratedKey,并且解析出要设置的参数值
public SQLRouteResult route(final String logicSQL, final List<Object> parameters, final SQLStatement sqlStatement) {
GeneratedKey generatedKey = null;
if (sqlStatement instanceof InsertStatement) {
generatedKey = getGenerateKey(shardingRule, (InsertStatement) sqlStatement, parameters);
}
SQLRouteResult result = new SQLRouteResult(sqlStatement, generatedKey);
ShardingConditions shardingConditions = OptimizeEngineFactory.newInstance(shardingRule, sqlStatement, parameters, generatedKey).optimize();
if (null != generatedKey) {
setGeneratedKeys(result, generatedKey);
}
RoutingResult routingResult = route(parameters, sqlStatement, shardingConditions);
SQLRewriteEngine rewriteEngine = new SQLRewriteEngine(shardingRule, logicSQL, databaseType, sqlStatement, shardingConditions, parameters);
boolean isSingleRouting = routingResult.isSingleRouting();
if (sqlStatement instanceof SelectStatement && null != ((SelectStatement) sqlStatement).getLimit()) {
processLimit(parameters, (SelectStatement) sqlStatement, isSingleRouting);
}
SQLBuilder sqlBuilder = rewriteEngine.rewrite(!isSingleRouting);
for (TableUnit each : routingResult.getTableUnits().getTableUnits()) {
result.getExecutionUnits().add(new SQLExecutionUnit(each.getDataSourceName(), rewriteEngine.generateSQL(each, sqlBuilder)));
}
if (showSQL) {
SQLLogger.logSQL(logicSQL, sqlStatement, result.getExecutionUnits());
}
return result;
}
InsertOptimizeEngine#optimize解析出需要拆分的条件,取出全部值表达式以及需要设置的具体值组成InsertShardingCondition,getShardingCondition方法主要用来获取表中每个字段以及需要设置的具体值,具体值的获取在Condition#getConditionValues中,字段标识的下标在解析sql表达式时已经创建过init(sqlExpression, 0);根据下标把具体的参数值获取出来最后保存在ListShardingValue,最后把结果保存在ShardingConditions返回。当generatedKey不为空时设置最新的generatedKeys
public ShardingConditions optimize() {
List<AndCondition> andConditions = insertStatement.getConditions().getOrCondition().getAndConditions();
List<InsertValue> insertValues = insertStatement.getInsertValues().getInsertValues();
List<ShardingCondition> result = new ArrayList<>(andConditions.size());
Iterator<Number> generatedKeys = null;
int count = 0;
for (AndCondition each : andConditions) {
InsertValue insertValue = insertValues.get(count);
List<Object> currentParameters = new ArrayList<>(insertValue.getParametersCount() + 1);
currentParameters.addAll(parameters.subList(count * insertValue.getParametersCount(), (count + 1) * insertValue.getParametersCount()));
String logicTableName = insertStatement.getTables().getSingleTableName();
Optional<Column> generateKeyColumn = shardingRule.getGenerateKeyColumn(logicTableName);
InsertShardingCondition insertShardingCondition;
if (-1 != insertStatement.getGenerateKeyColumnIndex() || !generateKeyColumn.isPresent()) {
insertShardingCondition = new InsertShardingCondition(insertValue.getExpression(), currentParameters);
} else {
if (null == generatedKeys) {
generatedKeys = generatedKey.getGeneratedKeys().iterator();
}
String expression;
Number currentGeneratedKey = generatedKeys.next();
if (0 == parameters.size()) {
expression = insertValue.getExpression().substring(0, insertValue.getExpression().length() - 1) + ", " + currentGeneratedKey.toString() + ")";
} else {
expression = insertValue.getExpression().substring(0, insertValue.getExpression().length() - 1) + ", ?)";
currentParameters.add(currentGeneratedKey);
}
insertShardingCondition = new InsertShardingCondition(expression, currentParameters);
insertShardingCondition.getShardingValues().add(getShardingCondition(generateKeyColumn.get(), currentGeneratedKey));
}
insertShardingCondition.getShardingValues().addAll(getShardingCondition(each));
result.add(insertShardingCondition);
count++;
}
return new ShardingConditions(result);
}