CMU数据库(15-445)Lab3- QUERY EXECUTION (2)

我们提供了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());

然后在进行插入

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxjxp.html