本文将带领大家从源码层面过一下 Drop Table 的实现,下面我们先回顾一下之前介绍过的 MiniOB 框架,SQL 语句的解析过程中,当前已经实现的只有 Parser、Resolver 和 Executor 模块。
首先看一下源代码相关的模块,如下图,在 src/observer/sql
文件夹下就是上面提到的蓝色部分模块,当前已经实现的重点模块在 executor
和 parser
下:
在 src/observer/sql/parser
文件夹下,包含 词法解析、语法解析和 resolver。我们本篇文章要实现的 Drop Table 实际上已经实现了词法解析和语法解析,大家可以从文件中找到词法解析的 TOKEN 和语法解析的 drop_table:
通常网络消息到达 parser 以后呢,会先到达 handle_event:
void ParseStage::handle_event(StageEvent *event)
{
LOG_TRACE("Enter\n");
RC rc = handle_request(event);
if (RC::SUCCESS != rc) {
callback_event(event, nullptr);
return;
}
CompletionCallback *cb = new (std::nothrow) CompletionCallback(this, nullptr);
if (cb == nullptr) {
LOG_ERROR("Failed to new callback for SQLStageEvent");
callback_event(event, nullptr);
return;
}
event->push_callback(cb);
resolve_stage_->handle_event(event);
event->done_immediate();
LOG_TRACE("Exit\n");
return;
}
然后进行请求处理:
RC ParseStage::handle_request(StageEvent *event)
{
SQLStageEvent *sql_event = static_cast<SQLStageEvent *>(event);
const std::string &sql = sql_event->sql();
Query *query_result = query_create();
if (nullptr == query_result) {
LOG_ERROR("Failed to create query.");
return RC::INTERNAL;
}
RC ret = parse(sql.c_str(), query_result);
if (ret != RC::SUCCESS) {
// set error information to event
sql_event->session_event()->set_response("Failed to parse sql\n");
query_destroy(query_result);
return RC::INTERNAL;
}
sql_event->set_query(query_result);
return RC::SUCCESS;
}
请求处理代码中,经过了词法语法解析:
RC ret = parse(sql.c_str(), query_result);
解析完成后会生成一个 Query,可以从 src/observer/sql/parser/parse_defs.h
中看到对应的定义:
// struct of flag and sql_struct
typedef struct Query {
enum SqlCommandFlag flag;
union Queries sstr;
} Query;
union Queries {
Selects selection;
Inserts insertion;
Deletes deletion;
Updates update;
CreateTable create_table;
DropTable drop_table;
CreateIndex create_index;
DropIndex drop_index;
DescTable desc_table;
LoadData load_data;
char *errors;
};
在 handle_event
中,完成了 handle_request
解析后,会进入下一个阶段 :resolve_stage_
resolve_stage_->handle_event(event);
在这个阶段,我们仍然从文件 src/observer/sql/parser/resolve_stage.cpp
中找到对应的 handle_event
,这个阶段有很多内容都没有实现,可以直接跳转到执行阶段。
void ResolveStage::handle_event(StageEvent *event)
{
LOG_TRACE("Enter\n");
SQLStageEvent *sql_event = static_cast<SQLStageEvent *>(event);
if (nullptr == sql_event) {
LOG_WARN("failed to get sql stage event");
return;
}
SessionEvent *session_event = sql_event->session_event();
Db *db = session_event->session()->get_current_db();
if (nullptr == db) {
LOG_ERROR("cannot current db");
return ;
}
Query *query = sql_event->query();
Stmt *stmt = nullptr;
RC rc = Stmt::create_stmt(db, *query, stmt);
if (rc != RC::SUCCESS && rc != RC::UNIMPLENMENT) {
LOG_WARN("failed to create stmt. rc=%d:%s", rc, strrc(rc));
session_event->set_response("FAILURE\n");
return;
}
sql_event->set_stmt(stmt);
query_cache_stage_->handle_event(sql_event);
LOG_TRACE("Exit\n");
return;
}
执行阶段的代码位于 src/observer/sql/executor/execute_stage.cpp
,从代码中可以找到对应的建表和删表操作,当前的删表操作还没有实现:
case SCF_CREATE_TABLE: {
do_create_table(sql_event);
} break;
case SCF_CREATE_INDEX: {
do_create_index(sql_event);
} break;
case SCF_SHOW_TABLES: {
do_show_tables(sql_event);
} break;
case SCF_DESC_TABLE: {
do_desc_table(sql_event);
} break;
case SCF_DROP_TABLE:
case SCF_DROP_INDEX:
从上面的代码中可以看到有很多功能已经实现,比如 create table
操作,所以 Drop Table 操作的实现比较简单,可以模仿着实现。
由于整个实现过程比较枯燥,这里只简单列一下大体思路,主要分为 5 步:
今天的内容大概就这些~
最后的最后,如果大家感兴趣,可以多关注和参与 OB 的活动:https://ask.oceanbase.com/t/topic/35601006。