Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sprint 3 #5

Merged
merged 18 commits into from
May 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,23 @@ set(
SOURCES
all_type_variant.hpp
null_value.hpp
operators/abstract_operator.cpp
operators/abstract_operator.hpp
operators/get_table.hpp
operators/print.cpp
operators/print.hpp
operators/table_scan.hpp
operators/table_wrapper.cpp
operators/table_wrapper.hpp
resolve_type.hpp
storage/abstract_attribute_vector.hpp
storage/abstract_segment.hpp
storage/chunk.cpp
storage/chunk.hpp
storage/dictionary_segment.cpp
storage/dictionary_segment.hpp
storage/reference_segment.cpp
storage/reference_segment.hpp
storage/storage_manager.cpp
storage/storage_manager.hpp
storage/table.cpp
Expand Down
27 changes: 27 additions & 0 deletions src/lib/operators/abstract_operator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "abstract_operator.hpp"

namespace opossum {

AbstractOperator::AbstractOperator(const std::shared_ptr<const AbstractOperator> left,
const std::shared_ptr<const AbstractOperator> right)
: _left_input(left), _right_input(right) {}

void AbstractOperator::execute() {
_output = _on_execute();
}

std::shared_ptr<const Table> AbstractOperator::get_output() const {
// TODO(student): You should place some meaningful checks here

return _output;
}

std::shared_ptr<const Table> AbstractOperator::_left_input_table() const {
return _left_input->get_output();
}

std::shared_ptr<const Table> AbstractOperator::_right_input_table() const {
return _right_input->get_output();
}

} // namespace opossum
59 changes: 59 additions & 0 deletions src/lib/operators/abstract_operator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#pragma once

#include <memory>

#include "types.hpp"

namespace opossum {

class Table;

// AbstractOperator is the abstract super class for all operators. All operators have up to two input tables and one
// output table. Their lifecycle has three phases:
// 1. The operator is constructed. Previous operators are not guaranteed to have already executed, so operators must not
// call get_output in their execute method
// 2. The execute method is called from the outside (usually by the scheduler). This is where the heavy lifting is done.
// By now, the input operators have already executed.
// 3. The consumer (usually another operator) calls get_output. This should be very cheap. It is only guaranteed to
// succeed if execute was called before. Otherwise, a nullptr or an empty table could be returned.
//
// Operators shall not be executed twice.

class AbstractOperator : private Noncopyable {
public:
AbstractOperator(const std::shared_ptr<const AbstractOperator> left = nullptr,
const std::shared_ptr<const AbstractOperator> right = nullptr);

virtual ~AbstractOperator() = default;

// We need to explicitly set the move constructor to default when we overwrite the copy constructor.
AbstractOperator(AbstractOperator&&) = default;
AbstractOperator& operator=(AbstractOperator&&) = default;

void execute();

// Returns the result of the operator.
std::shared_ptr<const Table> get_output() const;

// Get the input operators.
std::shared_ptr<const AbstractOperator> left_input() const;
std::shared_ptr<const AbstractOperator> right_input() const;

protected:
// Abstract method to actually execute the operator execute and get_output are split into two methods to allow for
// easier asynchronous execution.
virtual std::shared_ptr<const Table> _on_execute() = 0;

std::shared_ptr<const Table> _left_input_table() const;
std::shared_ptr<const Table> _right_input_table() const;

// Shared pointers to input operators. Can be nullptr, for example, if an operator is the leaf operator in the query
// plan or if the operator has only one input operator.
std::shared_ptr<const AbstractOperator> _left_input;
std::shared_ptr<const AbstractOperator> _right_input;

// Is nullptr until the operator is executed.
std::shared_ptr<const Table> _output;
};

} // namespace opossum
27 changes: 27 additions & 0 deletions src/lib/operators/get_table.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

#include "abstract_operator.hpp"
#include "utils/assert.hpp"

namespace opossum {

// Operator to retrieve a table from the StorageManager by specifying its name.
class GetTable : public AbstractOperator {
public:
explicit GetTable(const std::string& name) {
// TODO(student) implement it in a source file and change this to a declaration.
}

const std::string& table_name() const {
// TODO(student) implement it in a source file and change this to a declaration.
Fail("Implementation missing.");
}

protected:
std::shared_ptr<const Table> _on_execute() override {
// TODO(student) implement it in a source file and change this to a declaration.
Fail("Implementation missing.");
}
};

} // namespace opossum
110 changes: 110 additions & 0 deletions src/lib/operators/print.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include "print.hpp"

#include <iomanip>

#include "operators/table_wrapper.hpp"
#include "storage/abstract_segment.hpp"
#include "storage/table.hpp"
#include "type_cast.hpp"

namespace {

using namespace opossum; // NOLINT(build/namespaces)

std::string print_column_type(const std::shared_ptr<const Table>& table, const ColumnID column_id) {
auto stream = std::stringstream{};
stream << table->column_type(column_id);
if (table->column_nullable(column_id)) {
stream << "_null";
}

return stream.str();
}

} // namespace

namespace opossum {

Print::Print(const std::shared_ptr<const AbstractOperator> in, std::ostream& out) : AbstractOperator(in), _out(out) {}

void Print::print(std::shared_ptr<const Table>& table, std::ostream& out) {
auto table_wrapper = std::make_shared<TableWrapper>(table);
table_wrapper->execute();
Print(table_wrapper, out).execute();
}

std::shared_ptr<const Table> Print::_on_execute() {
auto widths = _column_string_widths(8, 20, _left_input_table());

// Print column headers.
_out << "=== Columns" << std::endl;
const auto left_column_count = _left_input_table()->column_count();
for (auto column_id = ColumnID{0}; column_id < left_column_count; ++column_id) {
_out << "|" << std::setw(widths[column_id]) << _left_input_table()->column_name(column_id) << std::setw(0);
}
_out << "|" << std::endl;
for (auto column_id = ColumnID{0}; column_id < left_column_count; ++column_id) {
_out << "|" << std::setw(widths[column_id]) << print_column_type(_left_input_table(), column_id) << std::setw(0);
}
_out << "|" << std::endl;

// print each chunk
const auto left_chunk_count = _left_input_table()->chunk_count();
for (auto chunk_id = ChunkID{0}; chunk_id < left_chunk_count; ++chunk_id) {
const auto chunk = _left_input_table()->get_chunk(chunk_id);

_out << "=== Chunk " << chunk_id << " === " << std::endl;

if (chunk->size() == 0) {
_out << "Empty chunk." << std::endl;
continue;
}

// Print the rows in the chunk.
const auto chunk_size = chunk->size();
for (size_t row = 0; row < chunk_size; ++row) {
_out << "|";
const auto column_count = chunk->column_count();
for (auto column_id = ColumnID{0}; column_id < column_count; ++column_id) {
// Yes, we use AbstractSegment::operator[] here, but since Print is not an operation that should be part of a
// regular query plan, let's keep things simple here.
_out << std::setw(widths[column_id]) << (*chunk->get_segment(column_id))[row] << "|" << std::setw(0);
}

_out << std::endl;
}
}

return _left_input_table();
}

// In order to print the table as an actual table, with columns being aligned, we need to calculate the number of
// characters in the printed representation of each column `min` and `max` can be used to limit the width of the
// columns - however, every column fits at least the column's name.
std::vector<uint16_t> Print::_column_string_widths(uint16_t min, uint16_t max,
const std::shared_ptr<const Table>& table) const {
auto widths = std::vector<uint16_t>(table->column_count());
// Calculate the length of the column name.
const auto column_count = table->column_count();
for (auto column_id = ColumnID{0}; column_id < column_count; ++column_id) {
widths[column_id] = std::max(min, static_cast<uint16_t>(table->column_name(column_id).size()));
}

// Go over all rows and find the maximum length of the printed representation of a value, up to max.
const auto left_chunk_count = _left_input_table()->chunk_count();
for (auto chunk_id = ChunkID{0}; chunk_id < left_chunk_count; ++chunk_id) {
auto chunk = _left_input_table()->get_chunk(chunk_id);

const auto column_count = chunk->column_count();
for (auto column_id = ColumnID{0}; column_id < column_count; ++column_id) {
for (auto row = size_t{0}; row < chunk->size(); ++row) {
auto cell_length =
static_cast<uint16_t>(boost::lexical_cast<std::string>((*chunk->get_segment(column_id))[row]).size());
widths[column_id] = std::max({min, widths[column_id], std::min(max, cell_length)});
}
}
}
return widths;
}

} // namespace opossum
24 changes: 24 additions & 0 deletions src/lib/operators/print.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include "abstract_operator.hpp"

namespace opossum {

/**
* operator to print the table with its data
*/
class Print : public AbstractOperator {
public:
explicit Print(const std::shared_ptr<const AbstractOperator> in, std::ostream& out = std::cout);

static void print(std::shared_ptr<const Table>& table, std::ostream& out = std::cout);

protected:
std::vector<uint16_t> _column_string_widths(uint16_t min, uint16_t max,
const std::shared_ptr<const Table>& table) const;
std::shared_ptr<const Table> _on_execute() override;

// stream to print the result
std::ostream& _out;
};
} // namespace opossum
37 changes: 37 additions & 0 deletions src/lib/operators/table_scan.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once

#include "abstract_operator.hpp"
#include "utils/assert.hpp"

namespace opossum {

class TableScan : public AbstractOperator {
public:
TableScan(const std::shared_ptr<const AbstractOperator>& in, const ColumnID column_id, const ScanType scan_type,
const AllTypeVariant search_value) {
// TODO(student) implement it in a source file and change this to a declaration.
}

ColumnID column_id() const {
// TODO(student) implement it in a source file and change this to a declaration.
Fail("Implementation missing.");
}

ScanType scan_type() const {
// TODO(student) implement it in a source file and change this to a declaration.
Fail("Implementation missing.");
}

const AllTypeVariant& search_value() const {
// TODO(student) implement it in a source file and change this to a declaration.
Fail("Implementation missing.");
}

protected:
std::shared_ptr<const Table> _on_execute() override {
// TODO(student) implement it in a source file and change this to a declaration.
Fail("Implementation missing.");
}
};

} // namespace opossum
10 changes: 10 additions & 0 deletions src/lib/operators/table_wrapper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "table_wrapper.hpp"

namespace opossum {

TableWrapper::TableWrapper(const std::shared_ptr<const Table>& table) : _table(table) {}

std::shared_ptr<const Table> TableWrapper::_on_execute() {
return _table;
}
} // namespace opossum
21 changes: 21 additions & 0 deletions src/lib/operators/table_wrapper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include "abstract_operator.hpp"
#include "utils/assert.hpp"

namespace opossum {

/**
* Operator that wraps a table.
*/
class TableWrapper : public AbstractOperator {
public:
explicit TableWrapper(const std::shared_ptr<const Table>& table);

protected:
std::shared_ptr<const Table> _on_execute() override;

// Table to retrieve
const std::shared_ptr<const Table> _table;
};
} // namespace opossum
43 changes: 43 additions & 0 deletions src/lib/storage/reference_segment.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "reference_segment.hpp"

#include "storage/table.hpp"
#include "utils/assert.hpp"

namespace opossum {

ReferenceSegment::ReferenceSegment(const std::shared_ptr<const Table>& referenced_table,
const ColumnID referenced_column_id, const std::shared_ptr<const PosList>& pos) {
// Implementation goes here
}

AllTypeVariant ReferenceSegment::operator[](const ChunkOffset chunk_offset) const {
// Implementation goes here
Fail("Implementation is missing.");
}

ChunkOffset ReferenceSegment::size() const {
// Implementation goes here
Fail("Implementation is missing.");
}

const std::shared_ptr<const PosList>& ReferenceSegment::pos_list() const {
// Implementation goes here
Fail("Implementation is missing.");
}

const std::shared_ptr<const Table>& ReferenceSegment::referenced_table() const {
// Implementation goes here
Fail("Implementation is missing.");
}

ColumnID ReferenceSegment::referenced_column_id() const {
// Implementation goes here
Fail("Implementation is missing.");
}

size_t ReferenceSegment::estimate_memory_usage() const {
// Implementation goes here
Fail("Implementation is missing.");
}

} // namespace opossum
Loading