javaweb
javaweb copied to clipboard
sharding-jdbc源码解析-sql解析(五)
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第一个标记类型创建出相应的解析器
-
解析器工厂(负责根据数据库类型选择具体解析器)分类:
SELECT<--->SelectParserFactory、INSERT<--->InsertParserFactory、UPDATE<--->UpdateParserFactory、DELETE<--->DeleteParserFactory、CREATE<--->CreateParserFactory、ALTER<--->AlterParserFactory、DROP<--->DropParserFactory、TRUNCATE<--->TruncateParserFactory
-
解析器分类:
SELECT<--->AbstractSelectParser、INSERT<--->AbstractInsertParser、UPDATE<--->AbstractUpdateParser、DELETE<--->AbstractDeleteParser、CREATE<--->AbstractCreateParser、ALTER<--->AbstractAlterParser、DROP<--->AbstractDropParser、TRUNCATE<--->AbstractTruncateParser
SQLParser
解析器
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()));
}
}
AbstractInsertClauseParserFacade
门面模式
@RequiredArgsConstructor
@Getter
public abstract class AbstractInsertClauseParserFacade {
private final InsertIntoClauseParser insertIntoClauseParser;
private final InsertColumnsClauseParser insertColumnsClauseParser;
private final InsertValuesClauseParser insertValuesClauseParser;
private final InsertSetClauseParser insertSetClauseParser;
}
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);
}