MySQL 源码解读之-语法解析(四)
在上篇文章中,我们分析了一条 sql 语句 select * from bank; 警告bison 语法解析器(MYSQLparser 函数)生成的AST 树的结构,如下图所示:
mysql 需要对这个AST 做进一步的处理,调用 LEX::make_sql_cmd 函数将当前的 AST树实例化Sql_cmd对象并将其分配给Lex。
Sql_cmd数据结构
Sql_cmd 类是 sql 命令的表现形式,此类是解析器和运行时之间的接口。解析器构建相应的Sql_cmd派生类,以表示已解析树中的Sql语句。Sql_cmd派生类中的execute()方法包含运行时实现。请注意,此接口用于最近实现的SQL语句,旧语句的代码倾向于加载具有更多属性的LEX结构。
通过对Sql_cmd进行子类化来实现新语句,因为这提高了代码的模块性(参见dispatch_command()中的“大开关”),并减少了LEX结构的总大小(因此节省了存储程序中的内存)。Sql_cmd派生类的推荐名称为Sql_cmd_<derived>。
class Sql_cmd { public: virtual enum_sql_command sql_command_code() const = 0; // 返回当前语句的命令码,如 SQLCOM_SELECT // 如果对象表示可准备语句,即用PREPARE语句准备并用EXECUTE语句执行的查询,则返回true。对于直接执行的常规语句(非可准备语句),返回False。如果语句是存储过程的一部分,则也是false bool needs_explicit_preparation() const { return m_owner != nullptr && !m_part_of_sp; } // 如果语句是正则的,则返回true. 既不是 prepare 语句也不是存储过程的一部分 bool is_regular() const { return m_owner == nullptr && !m_part_of_sp; } // 判断一个语句是是否是 prepare 语句 bool is_prepared() const { return m_prepared; } // prepare 这个语句 virtual bool prepare(THD *) { assert(!is_prepared()); set_prepared(); return false; } // 执行这个语句 virtual bool execute(THD *thd) = 0; // Command-specific reinitialization before execution of prepared statement virtual void cleanup(THD *) { m_secondary_engine = nullptr; } // 设置所属的prepare语句 void set_owner(Prepared_statement *stmt) { assert(!m_part_of_sp); m_owner = stmt; } // 设置所属的prepare语句 Prepared_statement *owner() const { return m_owner; } // 将语句标记为过程的一部分。这样的语句可以执行多次,第一次execute()调用也会准备它 void set_as_part_of_sp() { assert(!m_part_of_sp && m_owner == nullptr); m_part_of_sp = true; } // 判断语句是否是存储过程的一部分 bool is_part_of_sp() const { return m_part_of_sp; } // 判断一个语句是否DML virtual bool is_dml() const { return false; } // 如果实现为单表执行计划,则返回true,仅限DML语句 virtual bool is_single_table_plan() const { assert(is_dml()); return false; } virtual bool accept(THD *, Select_lex_visitor *) { return false; } virtual const MYSQL_LEX_CSTRING *eligible_secondary_storage_engine() const { return nullptr; } void disable_secondary_storage_engine() { assert(m_secondary_engine == nullptr); m_secondary_engine_enabled = false; } // 此语句是否禁用了辅助存储引擎的使用? bool secondary_storage_engine_disabled() const { return !m_secondary_engine_enabled; } void use_secondary_storage_engine(const handlerton *hton) { assert(m_secondary_engine_enabled); m_secondary_engine = hton; } bool using_secondary_storage_engine() const { return m_secondary_engine != nullptr; } // 获取用于执行此语句的辅助引擎的handlerton,如果未使用辅助引擎,则获取nullptr const handlerton *secondary_engine() const { return m_secondary_engine; } void set_optional_transform_prepared(bool value) { m_prepared_with_optional_transform = value; } bool is_optional_transform_prepared() { return m_prepared_with_optional_transform; } protected: Sql_cmd() : m_owner(nullptr), m_part_of_sp(false), m_prepared(false) {} virtual ~Sql_cmd() { // Sql_cmd对象在thd->mem_root中分配。在MySQL中,从未调用C++析构函数,而是简单地销毁底层MEM_ROOT。不要依赖析构函数进行任何清理。 assert(false); } /// 设置语句为 prepare 语句 void set_prepared() { m_prepared = true; } private: Prepared_statement *m_owner; // prepare 语句,如果不是 prepate 值为 NULL bool m_part_of_sp; // 是否是存储过程的一部分 bool m_prepared; // 已经被 prepare 的语句为 true // 指示辅助存储引擎是否可用于此语句。如果为false,则不会考虑使用辅助存储引擎来执行此语句。 bool m_secondary_engine_enabled{true}; // 跟踪语句是否准备了可选转换。 bool m_prepared_with_optional_transform{false}; // 用于执行此语句的辅助存储引擎(如果有),如果使用主引擎,则为nullptr。此属性在每次执行开始时重置。 const handlerton *m_secondary_engine{nullptr}; };
源码调试
我们此次把断点打到 LEX::make_sql_cmd 函数,然后执行 select * from bank; 如图所示,已经命中了该断点:
我们执行 s 进去make_sql_cmd 函数进行调试,可以看到该函数定义如下:
我们继续跟进 make_cmd 函数。如下图,调用了 PT_query_expression::contextualize 进行上下文初始化,这个我们之前分析的 AST 树是一致的。根节点的 m_qe 成员指向 PT_query_expression。
我们继续用 s 跟进,看看 PT_query_expression::contextualize 函数做了什么,如下所示:首先对 with 语句做上下文初始化,因为此处 with 语句为空,所以该函数什么也不做。接下来执行了 Parse_tree_node::contextualize 将节点标记为上下文化。
接下来还执行了 m_body->contextualize(pc) 。我们前面分析过此处的 m_body 指的是 PT_query_specification。所以该函数为 PT_query_specification::contextualize。我们继续 s 跟进去查看
分别对PT_select_item_list 和 from_clauser做上下文初始化。 该函数还对 into 等字句做上下文初始化,因为我们的例子不涉及该函数,此处我们不做分析。下文我们不再跟进一一分析,最终上下文初始化后的 AST 树如下:
参考:https://www.freesion.com/article/64711249190/
标签:语句,engine,const,cmd,语法,源码,bool,MySQL,secondary From: https://www.cnblogs.com/jkin/p/16899460.html