我们提供了ExecutionEngine(src / include / execution / execution_engine.h)作为帮助类。 它将输入的查询计划转换为查询执行程序,并执行直到收集所有结果。 您将需要修改ExecutionEngine以捕获执行程序引发的任何异常。
若要了解如何在查询执行期间创建excutors,请参阅ExecutorFactory(src / include / execution / executor_factory.h)帮助程序类。 此外,每个执行程序都有一个ExecutorContext(src / include / execution / executor_context.h)作为执行上下文环境。
SEQUENTIAL SCANS顺序扫描遍历一个表并每次返回一个元组。顺序扫描由SeqScanPlanNode指定。plan节点指定要迭代的表。节点还可以包含一个predicate;如果一个元组不满足predicate,则跳过它。
提示:您需要使用顺序扫描中的predicate来判断。特别需要注意的是AbstractExpression::Evaluate。会返回Value。需要使用GetAs<bool>变成bool类型。
实现这个实验其实并不难。重点就是实现之前要先梳理一下整个系统的一些设计模式。
以这一行为例利用了工厂设计模式
auto executor = ExecutorFactory::CreateExecutor(exec_ctx, plan);整个顺序扫描的思路非常简单。就是从头开始遍历整个表的所有tuple。找到满足要求的tuple。并将tuple中的满足要求的value和outSchema组合成新的tuple存入result就ok。
这里注意由于要进行遍历。所以要引入TableIterator。
这里附上最重要的Init实现。由于要遍历表的所有tuple。所以理应有一个table_info。同时要遍历整个表所以我们需要一个迭代器
void SeqScanExecutor::Init() { table_heap_ = exec_ctx_->GetCatalog()->GetTable(plan_->GetTableOid())->table_.get(); iter = table_heap_->Begin(exec_ctx_->GetTransaction()); }另一个实现就是一个tuple(其实就是一行)中的元素并不一定都是我们想要的。所以要有一个从tuple中获取和ouSchema中对应列的元素的函数这里就叫它getValuesFromTuple
std::vector<Value> SeqScanExecutor::getValuesFromTuple(const Tuple *tuple, const Schema *schema) { std::vector<Value> res; for (const Column &col : schema->GetColumns()) { Value val = tuple.GetValue(schema, schema->GetColIdx(col.GetName())); res.push_back(val); } return res; } INDEX SCANS就是利用加了索引的顺序扫描。
实现这个基本和上面的类似。只不过利用了索引
index_key = tuple_.KeyFromTuple(table_info->schema_, index_info->key_schema_, index_info->index_->GetKeyAttrs()); index_Expression->Evaluate(&index_key, &table_info->schema_).GetAs<bool>() INSERT插入将元组添加到表中。插入由InsertPlanNode指定。有两种类型的插入:1. 直接插入(只有插入语句),2. 非直接插入(从子语句中获取要插入的值)。例如INSERT INTO empty_table2 SELECT colA, colB FROM test_1 WHERE colA > 500需要先执行后面的select语句在进行insert。
实现先判断一下是否只有一个plan。
如果是的话则非常简单的插入就好了
if (is_rawInsert && num_inserted < num_values) { bool inserted = table_info->table_->InsertTuple(Tuple(raw_vals[num_inserted], &table_info->schema_), rid, exec_ctx_->GetTransaction()); BUSTUB_ASSERT(inserted, "Sequential insertion cannot fail"); for (auto index : table_Indexs) { index->index_->InsertEntry(Tuple(raw_vals[num_inserted], &table_info->schema_), *rid, exec_ctx_->GetTransaction()); } num_inserted++; return true; }否则的话则需要先执行后面的子plan
注意对于insert只能有一个子plan。这样就无需关注子plan的顺序问题
先执行子查询语句
execution_engine_ = std::make_unique<ExecutionEngine>(GetExecutorContext()->GetBufferPoolManager(), GetExecutorContext()->GetTransactionManager(), GetExecutorContext()->GetCatalog()); auto pNode = plan_->GetChildPlan(); execution_engine_->Execute(pNode, &result_set,GetExecutorContext()->GetTransaction(),GetExecutorContext());然后在进行插入