- 921. Minimum Add to Make Parentheses Valid 使括号有效的最少添加
- 915. Partition Array into Disjoint Intervals 分割数组
- 932. Beautiful Array 漂亮数组
- 940. Distinct Subsequences II 不同的子序列 II
Sharding-jdbc 官方文档讲的不是很全面和清楚,学习的时候特意再记录补充下
官方文档地址:http://shardingsphere.apache.org/index_zh.html
如果在大学期间学习过计算机编程原理课程,SQL的解析是比较简单的。 不过,它依然是一门完善的编程语言,因此对SQL的语法进行解析,与解析其他编程语言(如:Java语言、C语言、Go语言等)并无本质区别。
SQL解析引擎在 parsing包下:
1、 Lexer:词法解析器;
2、 Parser:SQL解析器;
两者都是解析器,区别在于 Lexer只做词法的解析,不关注上下文。讲字符串拆解成N个词法,而Perser在 Lexer的基础上,还需要理解SQL再进行解析
解析过程分为词法解析和语法解析。 词法解析器用于将SQL拆解为不可再分的原子符号,称为Token。并根据不同数据库方言所提供的字典,将其归类为关键字,表达式,字面量和操作符。 再使用语法解析器将SQL转换为抽象语法树。
例如,以下SQL:
SELECT id, name FROM t_user WHERE status = 'ACTIVE' AND age > 18
抽象语法树中的关键字的Token用绿色表示,变量的Token用红色表示,灰色表示需要进一步拆分。
最后,通过对抽象语法树的遍历去提炼分片所需的上下文,并标记有可能需要改写的位置。 供分片使用的解析上下文包含:
SQL的一次解析过程是不可逆的,一个个Token的按SQL原本的顺序依次进行解析,性能很高。
Lexer 会按照循序解析SQL,将sql字符串分解成 N 个分词(token),且这个过程是不可逆的
Lexer类继承图
可以看出,当前sharding-jdbc支持的数据库就是H2、Oracle、PostgreSQL、Mysql、SQLServer
token用于描述当前分解出的词法,包含3个属性:
1、 TokenTypetype:词法标记类型;
2、 Stringliterals:当前词法字面量;
3、 intendPosition:literals在SQL字符串中的位置(去除所有空格和注释);
TokenType 用于描述当前token的类型,分成 4 大类:
1、 DefaultKeyword:词法关键词;
已经定义了数据库的关键字,例如:SELECT 、FROM、WHERE、AND 2、 Literals:词法字面量标记;
sql分解出来的字符串实际值,例如关键字SELECT,table表名 3、 Symbol:词法符号标记;
Sql中的符号。例如 * 号,table1.name 中的点号,age,name中的逗号分隔符 4、 Assist:词法辅助标记;
Assist枚举只有2个属性,END和ERROR,END表示分解结束
Literals词法字面量标记,一共分成6种:
1、 IDENTIFIER:词法关键词;
2、 VARIABLE:变量;
3、 CHARS:字符串;
4、 HEX:十六进制;
5、 INT:整数;
6、 FLOAT:浮点数;
由于不同数据库遵守的 SQL 规范有所不同,所以不同的数据库对应存在不同的 Lexer实现,并且维护了各自对应的dictionary。
Sharding 会根据连接数据库的类型,选择相对应的Lexer实现类,并将对应的数据库词典覆盖父类Lexer的dictionary属性。Lexer内部根据相应数据库的dictionary与sql语句生成一个Tokenizer分词器进行分词。
public final class Tokenizer {
//SQL
private final String input;
//不同数据库对应的字典
private final Dictionary dictionary;
//偏移量
private final int offset;
}
分词器具体的方法如下:
public class Lexer {
private final String input;
private final Dictionary dictionary;
private int offset;
private Token currentToken;
public final void nextToken() {
this.skipIgnoredToken();
if (this.isVariableBegin()) {
this.currentToken = (new Tokenizer(this.input, this.dictionary, this.offset)).scanVariable();
} else if (this.isNCharBegin()) {
this.currentToken = (new Tokenizer(this.input, this.dictionary, ++this.offset)).scanChars();
} else if (this.isIdentifierBegin()) {
this.currentToken = (new Tokenizer(this.input, this.dictionary, this.offset)).scanIdentifier();
} else if (this.isHexDecimalBegin()) {
this.currentToken = (new Tokenizer(this.input, this.dictionary, this.offset)).scanHexDecimal();
} else if (this.isNumberBegin()) {
this.currentToken = (new Tokenizer(this.input, this.dictionary, this.offset)).scanNumber();
} else if (this.isSymbolBegin()) {
this.currentToken = (new Tokenizer(this.input, this.dictionary, this.offset)).scanSymbol();
} else if (this.isCharsBegin()) {
this.currentToken = (new Tokenizer(this.input, this.dictionary, this.offset)).scanChars();
} else {
if (!this.isEnd()) {
throw new SQLParsingException(this, Assist.ERROR);
}
this.currentToken = new Token(Assist.END, "", this.offset);
}
this.offset = this.currentToken.getEndPosition();
}
总结:Lexer主要的执行逻辑就是 nextToken() 方法,不断解析出当前 Token。Lexer的nextToken()方法里,使用 skipIgnoredToken() 方法跳过空格和注释的部分,通过 isXxx() 方法判断好下一个 Token 的类型,交给 Tokenizer 进行分词并跟新偏移量后返回 Token。
@Test
public void lexerTest() {
String sql = "SELECT id, name FROM t_user WHERE status = 'ACTIVE' AND age > 18";
MySQLLexer mySQLLexer = new MySQLLexer(sql);
boolean bool = true;
Token token;
do {
mySQLLexer.nextToken();
token = mySQLLexer.getCurrentToken();
System.out.println(JSONObject.toJSONString(token));
if (mySQLLexer.getCurrentToken().getType().toString().equals("END")) {
bool = false;
}
} while (bool);
}
Parser有三个组件
1、 SQLParsingengine:SQL解析引擎(掉用StatementParser解析SQL);
2、 SQLParser:SQL解析器(调用SQLParser解析SQL表达式);
3、 StatementParser:SQL语句解析(调用Lexer解析SQL词法解析器);
SQLParser 语法解析器,根据不同类型的语句有不同的语法解析器去解析成SQLStatement
可以看到,不同类型的sql,不同厂商的数据库,存在不同的处理解析器去解析,解析完成之后,会将SQL解析成SQLStatement。
SQLParsingEngine类 ,sql的解析引擎,其 parse() 方法作为 SQL 解析入口,本身不带复杂逻辑,通过调用对应的 SQLParser 进行 SQL 解析,返回SQLStatement
public SQLStatement parse(boolean useCache) {
//ShardingSphere将使用PreparedStatement的SQL解析的语法树放入缓存。 因此建议采用PreparedStatement这种SQL预编译的方式提升性能。
Optional<SQLStatement> cachedSQLStatement = this.getSQLStatementFromCache(useCache);
if (cachedSQLStatement.isPresent()) {
return (SQLStatement)cachedSQLStatement.get();
} else {
//词法解析
LexerEngine lexerEngine = LexerEngineFactory.newInstance(this.dbType, this.sql);
//语法解析
SQLStatement result = SQLParserFactory.newInstance(this.dbType, this.shardingRule, lexerEngine, this.shardingTableMetaData, this.sql).parse();
if (useCache) {
ParsingResultCache.getInstance().put(this.sql, result);
}
return result;
}
}
SQLStatement对象是个超类,具体实现类有很多。按照不同的语句,解析成不同的SQLStatement。
SQLStatement api:
不同的语句,ddl,dml,tcl等,有不同的语法解析器SQLParser去解析,与词法分析器一样使用工厂模式,词法分析器Lexer在解析Sql的时候,第一个分词就是SQL的具体类型(select,update),所以在执行sql的时候,首先调用词法分析器解析第一个分词,再按照不同类型的SQL选择不同的语法解析器。根据数据库类型,DB类型分词解析器获取语法解析器。
public final class SQLParserFactory {
public static SQLParser newInstance(DatabaseType dbType, ShardingRule shardingRule, LexerEngine lexerEngine, ShardingTableMetaData shardingTableMetaData, String sql) {
lexerEngine.nextToken();
TokenType tokenType = lexerEngine.getCurrentToken().getType();
if (DQLStatement.isDQL(tokenType)) {
return (SQLParser)(DatabaseType.MySQL == dbType ? new AntlrParsingEngine(dbType, sql, shardingRule, shardingTableMetaData) : getDQLParser(dbType, shardingRule, lexerEngine, shardingTableMetaData));
} else if (DMLStatement.isDML(tokenType)) {
return getDMLParser(dbType, tokenType, shardingRule, lexerEngine, shardingTableMetaData);
} else if (TCLStatement.isTCL(tokenType)) {
return new AntlrParsingEngine(dbType, sql, shardingRule, shardingTableMetaData);
} else if (DALStatement.isDAL(tokenType)) {
return getDALParser(dbType, (Keyword)tokenType, shardingRule, lexerEngine);
} else {
lexerEngine.nextToken();
TokenType secondaryTokenType = lexerEngine.getCurrentToken().getType();
if (DCLStatement.isDCL(tokenType, secondaryTokenType)) {
return new AntlrParsingEngine(dbType, sql, shardingRule, shardingTableMetaData);
} else if (DDLStatement.isDDL(tokenType, secondaryTokenType)) {
return new AntlrParsingEngine(dbType, sql, shardingRule, shardingTableMetaData);
} else if (TCLStatement.isTCLUnsafe(dbType, tokenType, lexerEngine)) {
return new AntlrParsingEngine(dbType, sql, shardingRule, shardingTableMetaData);
} else if (DefaultKeyword.SET.equals(tokenType)) {
return SetParserFactory.newInstance();
} else {
throw new SQLParsingUnsupportedException(tokenType);
}
}
}
}
一条sql在执行的时候,如何知道是什么类型的语句??
词法分析器Lexer在解析Sql的时候,第一个分词就是SQL的具体类型(select,update),所以在执行sql的时候,首先调用词法分析器解析第一个分词,获取语句类型,然后选择具体的语法解析器解析。和分词器引擎一样,SQL语句解析器也有自己的解析引擎
以下代码: if (!(ep = engOpen("\0"))) { fprintf(stderr, "\nCan't start MATLAB engine\n");
我在谈论一些网络事物,例如 http://uservoice.com/ 你能推荐任何其他类似的服务、网站,或者可能是(甚至更好)一个现成的引擎来部署在自己的服务器上? 实际上,更多关于系统的问题,可以
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我正在寻找一个矩阵表达式解析器/引擎。例如, 3 * A + B * C 其中 A、B、C 是矩阵是一个典型的表达式。这应该类似于(单值)数学表达式解析器/引擎,但应该处理矩阵值和变量。我已经用谷歌搜
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 想改进这个问题?将问题更新为 on-topic对于堆栈溢出。 5年前关闭。 Improve this qu
是否有基于 .net 的 cometd 引擎?比如 Ajax 推送引擎 那是免费和开源的吗? 最佳答案 轨道式 Orbited是一个 HTTP 守护进程,针对长期 cometd 连接进行了优化。它旨在
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
已结束。此问题正在寻求书籍、工具、软件库等的推荐。它不满足Stack Overflow guidelines 。目前不接受答案。 我们不允许提出寻求书籍、工具、软件库等推荐的问题。您可以编辑问题,以便
我正在寻找支持以下功能的 haml javascript“端口”: 存储在文件中的模板。 JSON 输入。 支持“集合”[{Booking},{Booking},{Booking}] 进行迭代处理。
我在 IronPython 中托管 IronPython。我没有找到使用等效的命令行参数初始化它的方法:-X:FullFrames . 我的代码有点像这样: import clr clr.AddRef
我想将我工作的公司的所有松散信息整合到一个知识库中。 Wiki 似乎是一种可行的方法,但大部分相关信息都隐藏在 PST 文件中,并且需要很长时间才能说服人们将他们的电子邮件(包括附件)手动翻译成 Wi
我已经使用缓存的 flutter 引擎 flutter 到现有的 native 应用程序(添加到应用程序)中。 override fun onCreate(savedInstanceState: Bu
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
我正在使用 Django Cassandra我已经定义了我的模型,我可以用它来命名一个表: class Meta: db_table = "table_name" 但是,Cassand
类似于 NoSQL 数据库,但适用于 OLAP。当然是开源的:) 编辑: OLAP 引擎在幕后使用关系数据库。例如 SAPBW 可以使用 Oracle 等。我的意思是一个没有这个底层关系数据库的 OL
我正在使用以下片段来 enable Razor templating in my solution (在 ASP.NET MVC3 之外)。是否可以轻松实现布局? 背景资料: 我在这一点上(模板编译成
我们目前使用闭源知识库解决方案,所见即所得创建文章是TinyMCE(看起来可能是修改/简化的)。 他们目前根本不允许更改它(添加插件等,除非您可以以某种方式注入(inject)插件)。 我确实拥有对
我正在评估我们的高性能电信应用程序的 BPEL 引擎,但性能似乎很差。我们评估了 Apache Ode、SunBPEL 引擎、Active BPEL 等。您知道任何更快的 BPEL 引擎实现或 C/C
Elastic / Lucene真的需要在文档中存储所有索引数据吗?您难道不就通过通过传递数据,以便Lucene may index the words into its hash table并为每个
我是 3D 游戏新手?我正在使用 Libgdx。如何计算像 Tetromino Revolution 游戏这样的透视相机的参数?请给我任何想法。 看图片:http://www.terminalstud
我是一名优秀的程序员,十分优秀!