老叶茶馆|ClickHouse和他的朋友们(8)纯手工打造的SQL解析器


北京联盟_本文原题:ClickHouse和他的朋友们(8)纯手工打造的SQL解析器
原文出处:https://bohutang.me/2020/07/25/clickhouse-and-friends-parser/
现实生活中的物品一旦被标记为“纯手工打造” , 给人的第一感觉就是“上乘之品” , 一个字“贵” , 比如北京老布鞋 。
但是在计算机世界里 , 如果有人告诉你 ClickHouse 的 SQL 解析器是纯手工打造的 , 是不是很惊讶!这个问题引起了不少网友的关注 , 所以本篇聊聊 ClickHouse 的纯手工解析器 , 看看它们的底层工作机制及优缺点 。
枯燥先从一个 SQL 开始:
EXPLAIN SELECT a,b FROM t1
token
首先对 SQL 里的字符逐个做判断 , 然后根据其关联性做 token 分割:
老叶茶馆|ClickHouse和他的朋友们(8)纯手工打造的SQL解析器
本文插图

比如连续的 WordChar , 那它就是 BareWord , 解析函数在 Lexer::nextTokenImpl , 解析调用栈:
DB::Lexer::nextTokenImpl Lexer.cpp:63
DB::Lexer::nextToken Lexer.cpp:52
DB::Tokens::operator[](unsigned long) TokenIterator.h:36
DB::TokenIterator::get TokenIterator.h:62
DB::TokenIterator::operator-> TokenIterator.h:64
DB::tryParseQuery(DB::IParser&, char const*&, char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, bool, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool, unsigned long, unsigned long) parseQuery.cpp:224
DB::parseQueryAndMovePosition(DB::IParser&, char const*&, char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool, unsigned long, unsigned long) parseQuery.cpp:314
DB::parseQuery(DB::IParser&, char const*, char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, unsigned long, unsigned long) parseQuery.cpp:332
DB::executeQueryImpl(const char *, const char *, DB::Context &, bool, DB::QueryProcessingStage::Enum, bool, DB::ReadBuffer *) executeQuery.cpp:272
DB::executeQuery(DB::ReadBuffer&, DB::WriteBuffer&, bool, DB::Context&, std::__1:: function<void (std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)>) executeQuery.cpp:731
DB::MySQLHandler::comQuery(DB::ReadBuffer&) MySQLHandler.cpp:313
DB::MySQLHandler::run MySQLHandler.cpp:150
ast
token 是最基础的元组 , 他们之间没有任何关联 , 只是一堆生冷的词组与符号 , 所以我们还需对其进行 语法解析 , 让这些 token 之间建立一定的关系 , 达到一个可描述的活力 。
ClickHouse 在解每一个 token 的时候 , 会根据当前的 token 进行状态空间进行预判(parse 返回 true 则进入子状态空间继续) , 然后决定状态跳转 , 比如:


推荐阅读