Initialized BeeDB

This commit is contained in:
Jan Mühlig 2020-04-26 16:38:08 +02:00
commit 867a3bb1c0
141 changed files with 17510 additions and 0 deletions

127
.clang-format Normal file
View File

@ -0,0 +1,127 @@
---
Language: Cpp
# BasedOnStyle: Microsoft
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: false
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 1000
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseTab: Never
...

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
*.o
build
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles/
Makefile
bee.db
cmake_install.cmake
lib/include/
lib/libsqlparser.so
patch/*

29
.pre-commit-hook Executable file
View File

@ -0,0 +1,29 @@
#!/bin/bash
STYLE=$(git config --get hooks.clangformat.style)
if [ -n "${STYLE}" ] ; then
STYLEARG="-style=${STYLE}"
else
STYLEARG=""
fi
format_file() {
file="${1}"
if [ -f $file ]; then
if [ "${file##*.}" = "cpp" ] || [ "${file##*.}" = "h" ] || [ "${file##*.}" = "hpp" ]; then
clang-format -i ${STYLEARG} ${1}
git add ${1}
fi
fi
}
case "${1}" in
--about )
echo "Runs clang-format on source files"
;;
* )
for file in `git diff-index --cached --name-only HEAD` ; do
format_file "${file}"
done
;;
esac

85
CMakeLists.txt Normal file
View File

@ -0,0 +1,85 @@
include(ExternalProject)
cmake_minimum_required(VERSION 3.9)
project(BeeDB)
## Set default settings
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "-pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-promo -Wstrict-overflow=5 -Wswitch-default -Wundef -Wno-unused -Wold-style-cast")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -g -DNDEBUG")
set(CMAKE_BUILD_TYPE DEBUG) # "Debug" is default build type, overwrite with 'cmake -DCMAKE_BUILD_TYPE=Release'
## SQL Parser as external project
ExternalProject_Add(
sql-parser
GIT_REPOSITORY "https://github.com/jangemue/sql-parser.git"
PREFIX "${CMAKE_CURRENT_BINARY_DIR}/lib/sql-parser/prefix"
TMP_DIR "${CMAKE_CURRENT_BINARY_DIR}/lib/sql-parser/tmp"
DOWNLOAD_DIR "${CMAKE_CURRENT_BINARY_DIR}/lib/sql-parser/download"
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/lib/sql-parser/src"
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/lib/sql-parser/bin"
)
## Include and link directories
include_directories(${PROJECT_SOURCE_DIR}/src/include ${PROJECT_SOURCE_DIR}/lib/ ${CMAKE_CURRENT_BINARY_DIR}/lib/sql-parser/src/src)
link_directories(${CMAKE_CURRENT_BINARY_DIR}/lib ${CMAKE_CURRENT_BINARY_DIR}/lib/sql-parser/bin/lib)
## BeeDB sources
add_executable(beedb
src/beedb.cpp
src/database.cpp
src/disk/storage_manager.cpp
src/disk/buffer_manager.cpp
src/disk/lru_strategy.cpp
src/disk/lru_k_strategy.cpp
src/disk/lfu_strategy.cpp
src/table/table.cpp
src/table/column.cpp
src/table/value.cpp
src/table/table_disk_manager.cpp
src/execution/binary_operator.cpp
src/execution/sequential_scan_operator.cpp
src/execution/index_scan_operator.cpp
src/execution/create_table_operator.cpp
src/execution/create_index_operator.cpp
src/execution/insert_operator.cpp
src/execution/selection_operator.cpp
src/execution/projection_operator.cpp
src/execution/nested_loops_join_operator.cpp
src/execution/hash_join_operator.cpp
src/execution/limit_operator.cpp
src/execution/build_index_operator.cpp
src/execution/order_operator.cpp
src/execution/aggregate_operator.cpp
src/execution/cross_product_operator.cpp
src/execution/tuple_buffer_operator.cpp
src/execution/add_to_index_operator.cpp
src/execution/update_operator.cpp
src/expression/attribute.cpp
src/expression/predicate.cpp
src/plan/physical/plan.cpp
src/plan/logical/builder.cpp
src/plan/physical/builder.cpp
src/io/executor.cpp
src/io/file_executor.cpp
src/io/user_console.cpp
src/io/printing_executor.cpp
src/io/result_output_formatter.cpp
src/io/command/commander.cpp
src/io/command/custom_commands.cpp
src/util/text_table.cpp
src/util/ini_parser.cpp
src/parser/query_parser.cpp
src/parser/hsql_parser.cpp
src/plan/logical/plan.cpp
src/plan/optimizer/optimizer.cpp
)
## Build target
add_dependencies(beedb sql-parser)
target_link_libraries(beedb sqlparser)
## Git install hook target
add_custom_target(git-hook cp ${PROJECT_SOURCE_DIR}/.pre-commit-hook ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit && chmod +x ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit)

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 TheScriptbot
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

78
README.md Normal file
View File

@ -0,0 +1,78 @@
# BeeDB
BeeDB is a software project that teaches students the architecture and implementation of DataBase Management Systems.
This project is related to the Basic Module *Architecture & Implementation of DBMS*. The course is usually teached every summer term, see [dbis page of TU Dortmund](http://dbis.cs.tu-dortmund.de/cms/en/teaching/index.html) for more information.
**Attention: Please do not publish and share your solution with other students!**
## Dependencies
* `git`
* `cmake` (at least version `3.9`)
* `build-essential`
* `bison` and `flex`
## How to build
* `cmake .`
* `make`
**OR**, if you prefer a separate `build` folder:
* `mkdir build && cd build`
* `cmake ..`
* `make`
Default build is in `Debug` mode.
If you want to build in `Release` mode use `cmake . -DCMAKE_BUILD_TYPE=Release` or set `CMAKE_BUILD_TYPE` in `CMakeLists.txt`.
## How to use
Usage: beedb [options] db-file
Positional arguments:
db-file File the database is stored in. Default: bee.db
Optional arguments:
-h --help show this help message and exit
-l --load Load SQL file into database.
-q --query Execute Query.
-c --console Run console after loading file or executing query.
--buffer-manager-frames Number of frames within the frame buffer.
--scan-page-limit Number of pages the SCAN operator can pin at a time.
--enable-index-scan Enable index scan and use whenever possible.
--enable-hash-join Enable hash join and use whenever possible.
--stats Print all execution statistics
## Configuration
Some configuration outside the console arguments is stored in the file `beedb.ini`.
* The number of pages stored as frames in the buffer manager (`buffer manager.frames`)
* The replacement strategy of frames in the buffer manager (`buffer manager.strategy`)
* The `k` parameter for `LRU-K` replacement strategy (`buffer manager.k`)
* The number of how many pages can be pinned by a scan at a time (`scan.page-limit`)
* Enable or disable usage of index scan (`scan.enable-index-scan`)
* Enable or disable usage of hash join (`join.enable-hash-join`)
## Non-SQL Commands
* `:explain [plan,graph]`: prints the query plan, either as a table or a graph (a list of nodes and edges)
* `:get [option-name]`: prints either all or the secified option of the database configuration
* `:set option-name numerical-value`: changes the specified option. Only numerical values are valid
* `:show [tables,indices,columns]`: A quick way to show available tables, their columns or indices
## Examples
##### Import
`./beedb -l movies.sql`
##### Run a single query
`./beedb -q "SELECT * FROM movie;"`
##### Open the BeeDB Console
`./beedb`
##### Run a query and open console afterwards
`./beedb -q "SELECT * FROM movie;" -c`
# For developers
* If you want to commit to the repository please `make git-hook` before commit.
# Credits
* Thanks to Hyrise for the SQL parser (MIT, [See on GitHub](https://github.com/hyrise/sql-parser))
* Thanks to p-ranav for argparse (MIT, [See on GitHub](https://github.com/p-ranav/argparse))

14
beedb.ini Normal file
View File

@ -0,0 +1,14 @@
[buffer manager]
frames = 256
strategy = LRU ;LRU-K | LFU | LRU
k = 2 ; LRU-K parameter
[scan]
page-limit = 64
enable-index-scan = 0 ; 1 for enable index scan
[join]
enable-hash-join = 0 ; 1 for enable hash join
[execution]
print-statistics = 0 ; 1 for printing all execution statistics

539
lib/argparse/argparse.hpp Normal file
View File

@ -0,0 +1,539 @@
/*
__ _ _ __ __ _ _ __ __ _ _ __ ___ ___
/ _` | '__/ _` | '_ \ / _` | '__/ __|/ _ \ Argument Parser for Modern C++
| (_| | | | (_| | |_) | (_| | | \__ \ __/ http://github.com/p-ranav/argparse
\__,_|_| \__, | .__/ \__,_|_| |___/\___|
|___/|_|
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2019 Pranav Srinivas Kumar <pranav.srinivas.kumar@gmail.com>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <algorithm>
#include <any>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <memory>
#include <numeric>
#include <sstream>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <vector>
namespace argparse {
namespace details { // namespace for helper methods
template <typename... Ts> struct is_container_helper {};
template <typename T, typename _ = void>
struct is_container : std::false_type {};
template <> struct is_container<std::string> : std::false_type {};
template <typename T>
struct is_container<
T,
std::conditional_t<false,
is_container_helper<typename T::value_type,
decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end()),
decltype(std::declval<T>().size())>,
void>> : public std::true_type {};
template <typename T>
static constexpr bool is_container_v = is_container<T>::value;
template <typename T>
using enable_if_container = std::enable_if_t<is_container_v<T>, T>;
template <typename T>
using enable_if_not_container = std::enable_if_t<!is_container_v<T>, T>;
} // namespace
class Argument {
friend class ArgumentParser;
public:
Argument() = default;
template <typename... Args>
explicit Argument(Args... args)
: mNames({std::move(args)...}), mIsOptional((is_optional(args) || ...)) {
std::sort(
mNames.begin(), mNames.end(), [](const auto &lhs, const auto &rhs) {
return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size();
});
}
Argument &help(std::string aHelp) {
mHelp = std::move(aHelp);
return *this;
}
Argument &default_value(std::any aDefaultValue) {
mDefaultValue = std::move(aDefaultValue);
return *this;
}
Argument &required() {
mIsRequired = true;
return *this;
}
Argument &implicit_value(std::any aImplicitValue) {
mImplicitValue = std::move(aImplicitValue);
mNumArgs = 0;
return *this;
}
Argument &action(std::function<std::any(const std::string &)> aAction) {
mAction = std::move(aAction);
return *this;
}
Argument &nargs(size_t aNumArgs) {
mNumArgs = aNumArgs;
return *this;
}
template <typename Iterator>
Iterator consume(Iterator start, Iterator end, std::string usedName = {}) {
if (mIsUsed) {
throw std::runtime_error("Duplicate argument");
}
mIsUsed = true;
mUsedName = std::move(usedName);
if (mNumArgs == 0) {
mValues.emplace_back(mImplicitValue);
return start;
} else if (mNumArgs <= static_cast<size_t>(std::distance(start, end))) {
end = std::next(start, mNumArgs);
if (std::any_of(start, end, Argument::is_optional)) {
throw std::runtime_error("optional argument in parameter sequence");
}
std::transform(start, end, std::back_inserter(mValues), mAction);
return end;
} else if (mDefaultValue.has_value()) {
return start;
} else {
throw std::runtime_error("Too few arguments");
}
}
/*
* @throws std::runtime_error if argument values are not valid
*/
void validate() const {
if (mIsOptional) {
if (mIsUsed && mValues.size() != mNumArgs && !mDefaultValue.has_value()) {
std::stringstream stream;
stream << mUsedName << ": expected " << mNumArgs
<< " argument(s). " << mValues.size() << " provided.";
throw std::runtime_error(stream.str());
} else {
// TODO: check if an implicit value was programmed for this argument
if (!mIsUsed && !mDefaultValue.has_value() && mIsRequired) {
std::stringstream stream;
stream << mNames[0] << ": required.";
throw std::runtime_error(stream.str());
}
if (mIsUsed && mIsRequired && mValues.size() == 0) {
std::stringstream stream;
stream << mUsedName << ": no value provided.";
throw std::runtime_error(stream.str());
}
}
} else {
if (mValues.size() != mNumArgs && !mDefaultValue.has_value()) {
std::stringstream stream;
stream << mUsedName << ": expected " << mNumArgs
<< " argument(s). " << mValues.size() << " provided.";
throw std::runtime_error(stream.str());
}
}
}
size_t get_arguments_length() const {
return std::accumulate(std::begin(mNames), std::end(mNames), size_t(0),
[](const auto &sum, const auto &s) {
return sum + s.size() +
1; // +1 for space between names
});
}
friend std::ostream &operator<<(std::ostream &stream,
const Argument &argument) {
std::stringstream nameStream;
std::copy(std::begin(argument.mNames), std::end(argument.mNames),
std::ostream_iterator<std::string>(nameStream, " "));
stream << nameStream.str() << "\t" << argument.mHelp;
if (argument.mIsRequired)
stream << "[Required]";
stream << "\n";
return stream;
}
template <typename T> bool operator!=(const T &aRhs) const {
return !(*this == aRhs);
}
/*
* Entry point for template non-container types
* @throws std::logic_error in case of incompatible types
*/
template <typename T>
std::enable_if_t<!details::is_container_v<T>, bool> operator==(const T &aRhs) const {
return get<T>() == aRhs;
}
/*
* Template specialization for containers
* @throws std::logic_error in case of incompatible types
*/
template <typename T>
std::enable_if_t<details::is_container_v<T>, bool> operator==(const T &aRhs) const {
using ValueType = typename T::value_type;
auto tLhs = get<T>();
if (tLhs.size() != aRhs.size())
return false;
else {
return std::equal(std::begin(tLhs), std::end(tLhs), std::begin(aRhs),
[](const auto &lhs, const auto &rhs) {
return std::any_cast<const ValueType &>(lhs) == rhs;
});
}
}
private:
static bool is_integer(const std::string &aValue) {
if (aValue.empty() ||
((!isdigit(aValue[0])) && (aValue[0] != '-') && (aValue[0] != '+')))
return false;
char *tPtr;
strtol(aValue.c_str(), &tPtr, 10);
return (*tPtr == 0);
}
static bool is_float(const std::string &aValue) {
std::istringstream tStream(aValue);
float tFloat;
// noskipws considers leading whitespace invalid
tStream >> std::noskipws >> tFloat;
// Check the entire string was consumed
// and if either failbit or badbit is set
return tStream.eof() && !tStream.fail();
}
// If an argument starts with "-" or "--", then it's optional
static bool is_optional(const std::string &aName) {
return (!aName.empty() && aName[0] == '-' && !is_integer(aName) &&
!is_float(aName));
}
static bool is_positional(const std::string &aName) {
return !is_optional(aName);
}
/*
* Getter for template non-container types
* @throws std::logic_error in case of incompatible types
*/
template <typename T> details::enable_if_not_container<T> get() const {
if (!mValues.empty()) {
return std::any_cast<T>(mValues.front());
}
if (mDefaultValue.has_value()) {
return std::any_cast<T>(mDefaultValue);
}
throw std::logic_error("No value provided");
}
/*
* Getter for container types
* @throws std::logic_error in case of incompatible types
*/
template <typename CONTAINER> details::enable_if_container<CONTAINER> get() const {
using ValueType = typename CONTAINER::value_type;
CONTAINER tResult;
if (!mValues.empty()) {
std::transform(
std::begin(mValues), std::end(mValues), std::back_inserter(tResult),
[](const auto &value) { return std::any_cast<ValueType>(value); });
return tResult;
}
if (mDefaultValue.has_value()) {
const auto &tDefaultValues =
std::any_cast<const CONTAINER &>(mDefaultValue);
std::transform(std::begin(tDefaultValues), std::end(tDefaultValues),
std::back_inserter(tResult), [](const auto &value) {
return std::any_cast<ValueType>(value);
});
return tResult;
}
throw std::logic_error("No value provided");
}
std::vector<std::string> mNames;
std::string mUsedName;
std::string mHelp;
std::any mDefaultValue;
std::any mImplicitValue;
std::function<std::any(const std::string &)> mAction =
[](const std::string &aValue) { return aValue; };
std::vector<std::any> mValues;
std::vector<std::string> mRawValues;
size_t mNumArgs = 1;
bool mIsOptional = false;
bool mIsRequired = false;
bool mIsUsed = false; // relevant for optional arguments. True if used by user
public:
static constexpr auto mHelpOption = "-h";
static constexpr auto mHelpOptionLong = "--help";
};
class ArgumentParser {
public:
explicit ArgumentParser(std::string aProgramName = {})
: mProgramName(std::move(aProgramName)) {
add_argument(Argument::mHelpOption, Argument::mHelpOptionLong)
.help("show this help message and exit")
.nargs(0)
.default_value(false)
.implicit_value(true);
}
// Parameter packing
// Call add_argument with variadic number of string arguments
template <typename... Targs> Argument &add_argument(Targs... Fargs) {
std::shared_ptr<Argument> tArgument =
std::make_shared<Argument>(std::move(Fargs)...);
if (tArgument->mIsOptional)
mOptionalArguments.emplace_back(tArgument);
else
mPositionalArguments.emplace_back(tArgument);
for (const auto &mName : tArgument->mNames) {
mArgumentMap.insert_or_assign(mName, tArgument);
}
return *tArgument;
}
// Parameter packed add_parents method
// Accepts a variadic number of ArgumentParser objects
template <typename... Targs> void add_parents(Targs... Fargs) {
const auto tNewParentParsers = {Fargs...};
for (const auto &tParentParser : tNewParentParsers) {
const auto &tPositionalArguments = tParentParser.mPositionalArguments;
std::copy(std::begin(tPositionalArguments),
std::end(tPositionalArguments),
std::back_inserter(mPositionalArguments));
const auto &tOptionalArguments = tParentParser.mOptionalArguments;
std::copy(std::begin(tOptionalArguments), std::end(tOptionalArguments),
std::back_inserter(mOptionalArguments));
const auto &tArgumentMap = tParentParser.mArgumentMap;
for (const auto &[tKey, tValue] : tArgumentMap) {
mArgumentMap.insert_or_assign(tKey, tValue);
}
}
std::move(std::begin(tNewParentParsers), std::end(tNewParentParsers),
std::back_inserter(mParentParsers));
}
/* Call parse_args_internal - which does all the work
* Then, validate the parsed arguments
* This variant is used mainly for testing
* @throws std::runtime_error in case of any invalid argument
*/
void parse_args(const std::vector<std::string> &aArguments) {
parse_args_internal(aArguments);
parse_args_validate();
}
/* Main entry point for parsing command-line arguments using this
* ArgumentParser
* @throws std::runtime_error in case of any invalid argument
*/
void parse_args(int argc, const char *const argv[]) {
std::vector<std::string> arguments;
std::copy(argv, argv + argc, std::back_inserter(arguments));
parse_args(arguments);
}
/* Getter enabled for all template types other than std::vector and std::list
* @throws std::logic_error in case of an invalid argument name
* @throws std::logic_error in case of incompatible types
*/
template <typename T = std::string> T get(const std::string &aArgumentName) {
auto tIterator = mArgumentMap.find(aArgumentName);
if (tIterator != mArgumentMap.end()) {
return tIterator->second->get<T>();
}
throw std::logic_error("No such argument");
}
/* Indexing operator. Return a reference to an Argument object
* Used in conjuction with Argument.operator== e.g., parser["foo"] == true
* @throws std::logic_error in case of an invalid argument name
*/
Argument &operator[](const std::string &aArgumentName) {
auto tIterator = mArgumentMap.find(aArgumentName);
if (tIterator != mArgumentMap.end()) {
return *(tIterator->second);
}
throw std::logic_error("No such argument");
}
// Printing the one and only help message
// I've stuck with a simple message format, nothing fancy.
// TODO: support user-defined help and usage messages for the ArgumentParser
std::string print_help() {
std::stringstream stream;
stream << std::left;
stream << "Usage: " << mProgramName << " [options] ";
size_t tLongestArgumentLength = get_length_of_longest_argument();
for (const auto &argument : mPositionalArguments) {
stream << argument->mNames.front() << " ";
}
stream << "\n\n";
if (!mPositionalArguments.empty())
stream << "Positional arguments:\n";
for (const auto &mPositionalArgument : mPositionalArguments) {
stream.width(tLongestArgumentLength);
stream << *mPositionalArgument;
}
if (!mOptionalArguments.empty())
stream << (mPositionalArguments.empty() ? "" : "\n")
<< "Optional arguments:\n";
for (const auto &mOptionalArgument : mOptionalArguments) {
stream.width(tLongestArgumentLength);
stream << *mOptionalArgument;
}
std::cout << stream.str();
return stream.str();
}
private:
/*
* @throws std::runtime_error in case of any invalid argument
*/
void parse_args_internal(const std::vector<std::string> &aArguments) {
if (mProgramName.empty() && !aArguments.empty()) {
mProgramName = aArguments.front();
}
auto end = std::end(aArguments);
auto positionalArgumentIt = std::begin(mPositionalArguments);
for (auto it = std::next(std::begin(aArguments)); it != end;) {
const auto &tCurrentArgument = *it;
if (tCurrentArgument == Argument::mHelpOption ||
tCurrentArgument == Argument::mHelpOptionLong) {
throw std::runtime_error("help called");
}
if (Argument::is_positional(tCurrentArgument)) {
if (positionalArgumentIt == std::end(mPositionalArguments)) {
throw std::runtime_error(
"Maximum number of positional arguments exceeded");
}
auto tArgument = *(positionalArgumentIt++);
it = tArgument->consume(it, end);
} else if (auto tIterator = mArgumentMap.find(tCurrentArgument);
tIterator != mArgumentMap.end()) {
auto tArgument = tIterator->second;
it = tArgument->consume(std::next(it), end, tCurrentArgument);
} else if (const auto &tCompoundArgument = tCurrentArgument;
tCompoundArgument.size() > 1 && tCompoundArgument[0] == '-' &&
tCompoundArgument[1] != '-') {
++it;
for (size_t j = 1; j < tCompoundArgument.size(); j++) {
auto iCurrentArgument = std::string{'-', tCompoundArgument[j]};
if (auto iIterator = mArgumentMap.find(iCurrentArgument);
iIterator != mArgumentMap.end()) {
auto tArgument = iIterator->second;
it = tArgument->consume(it, end, iCurrentArgument);
} else {
throw std::runtime_error("Unknown argument");
}
}
} else {
throw std::runtime_error("Unknown argument");
}
}
}
/*
* @throws std::runtime_error in case of any invalid argument
*/
void parse_args_validate() {
// Check if all arguments are parsed
std::for_each(std::begin(mArgumentMap), std::end(mArgumentMap),
[](const auto &argPair) {
const auto &tArgument = argPair.second;
tArgument->validate();
});
}
// Used by print_help.
size_t get_length_of_longest_argument() {
if (mArgumentMap.empty())
return 0;
std::vector<size_t> argumentLengths(mArgumentMap.size());
std::transform(std::begin(mArgumentMap), std::end(mArgumentMap),
std::begin(argumentLengths), [](const auto &argPair) {
const auto &tArgument = argPair.second;
return tArgument->get_arguments_length();
});
return *std::max_element(std::begin(argumentLengths),
std::end(argumentLengths));
}
std::string mProgramName;
std::vector<ArgumentParser> mParentParsers;
std::vector<std::shared_ptr<Argument>> mPositionalArguments;
std::vector<std::shared_ptr<Argument>> mOptionalArguments;
std::map<std::string, std::shared_ptr<Argument>> mArgumentMap;
};
#define PARSE_ARGS(parser, argc, argv) \
try { \
parser.parse_args(argc, argv); \
} catch (const std::runtime_error &err) { \
std::cout << err.what() << std::endl; \
parser.print_help(); \
exit(0); \
}
} // namespace argparse

155
src/beedb.cpp Normal file
View File

@ -0,0 +1,155 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <argparse/argparse.hpp>
#include <config.h>
#include <database.h>
#include <io/file_executor.h>
#include <io/printing_executor.h>
#include <io/user_console.h>
#include <parser/query_parser.h>
#include <string>
#include <util/ini_parser.h>
int main(int arg_count, char **args)
{
// Read configuration file.
beedb::util::IniParser ini_parser{"beedb.ini"};
if (ini_parser.empty())
{
std::cout << "[Warning] Missing configuration file beedb.ini" << std::endl;
}
const auto buffer_frames = ini_parser.get<std::uint32_t>("buffer manager", "frames", 256u);
const auto scan_page_limit = ini_parser.get<std::uint32_t>("scan", "page-limit", 64u);
const auto enable_index_scan = ini_parser.get<bool>("scan", "enable-index-scan", false);
const auto buffer_replacement_strategy = ini_parser.get<std::string>("buffer manager", "strategy", "LRU");
const auto lru_k = ini_parser.get<std::uint32_t>("buffer manager", "k", 2u);
const auto enable_hash_join = ini_parser.get<bool>("join", "enable-hash-join", false);
const auto print_statistics = ini_parser.get<bool>("execution", "print-statistics", false);
// Parse command line arguments
argparse::ArgumentParser argument_parser("beedb");
argument_parser.add_argument("db-file")
.help("File the database is stored in. Default: bee.db")
.default_value(std::string("bee.db"));
argument_parser.add_argument("-l", "--load").help("Load SQL file into database.").default_value(std::string(""));
argument_parser.add_argument("-q", "--query").help("Execute Query.").default_value(std::string(""));
argument_parser.add_argument("-c", "--console")
.help("Run console after loading file or executing query.")
.implicit_value(true)
.default_value(false);
argument_parser.add_argument("--buffer-manager-frames")
.help("Number of frames within the frame buffer.")
.default_value(buffer_frames)
.action([](const std::string &value) { return std::uint32_t(std::stoi(value)); });
argument_parser.add_argument("--scan-page-limit")
.help("Number of pages the SCAN operator can pin at a time.")
.default_value(scan_page_limit)
.action([](const std::string &value) { return std::uint32_t(std::stoi(value)); });
argument_parser.add_argument("--enable-index-scan")
.help("Enable index scan and use whenever possible.")
.implicit_value(true)
.default_value(enable_index_scan);
argument_parser.add_argument("--enable-hash-join")
.help("Enable hash join and use whenever possible.")
.implicit_value(true)
.default_value(enable_hash_join);
argument_parser.add_argument("--stats")
.help("Print all execution statistics")
.implicit_value(true)
.default_value(print_statistics);
try
{
argument_parser.parse_args(arg_count, args);
}
catch (std::runtime_error &)
{
argument_parser.print_help();
return 1;
}
std::regex lfu_regex("lfu", std::regex::icase);
std::regex lru_k_regex("lru-k", std::regex::icase);
std::smatch match;
beedb::Config::BufferReplacementStrategy strategy = beedb::Config::LRU;
if (std::regex_match(buffer_replacement_strategy, match, lfu_regex))
{
strategy = beedb::Config::LFU;
}
else if (std::regex_match(buffer_replacement_strategy, match, lru_k_regex))
{
strategy = beedb::Config::LRU_K;
}
beedb::Config config{};
config.set(beedb::Config::k_BufferFrames, argument_parser.get<std::uint32_t>("--buffer-manager-frames"),
beedb::Config::ConfigMapValue::immutable);
config.set(beedb::Config::k_BufferReplacementStrategy, strategy, beedb::Config::ConfigMapValue::immutable);
config.set(beedb::Config::k_LRU_K, lru_k, beedb::Config::ConfigMapValue::immutable);
config.set(beedb::Config::k_ScanPageLimit, argument_parser.get<std::uint32_t>("--scan-page-limit"),
beedb::Config::ConfigMapValue::immutable);
config.set(beedb::Config::k_OptimizationEnableIndexScan, argument_parser.get<bool>("--enable-index-scan"));
config.set(beedb::Config::k_OptimizationEnableHashJoin, argument_parser.get<bool>("--enable-hash-join"));
config.set(beedb::Config::k_OptimizationDisableOptimization,
true); // true (at first), to disable optimization during boot
config.set(beedb::Config::k_CheckFinalPlan, false);
config.set(beedb::Config::k_PrintExecutionStatistics, argument_parser.get<bool>("--stats"));
const auto database_file_name = argument_parser.get<std::string>("db-file");
const auto sql_file = argument_parser.get<std::string>("-l");
const auto query = argument_parser.get<std::string>("-q");
const auto is_console = argument_parser.get<bool>("-c");
beedb::Database database(config, database_file_name);
database.boot();
// re-enable optimization for user-queries, after boot code ran:
config.set(beedb::Config::k_OptimizationDisableOptimization, false);
// re-enable checks on all plans, when in debug mode:
assert(config.set(beedb::Config::k_CheckFinalPlan, true));
if (sql_file.empty() == false)
{
beedb::io::FileExecutor file_importer(database);
file_importer.import_file(sql_file);
}
if (query.empty() == false)
{
beedb::io::PrintingExecutor printing_executor(database);
printing_executor.execute(beedb::io::Query{query});
}
if ((sql_file.empty() == false || query.empty() == false) && is_console == false)
{
return 0;
}
beedb::io::UserConsole user_console(database);
user_console.wait_for_input();
return 0;
}

296
src/database.cpp Normal file
View File

@ -0,0 +1,296 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <cassert>
#include <config.h>
#include <database.h>
#include <disk/buffer_replacement_strategy.h>
#include <disk/lfu_strategy.h>
#include <disk/lru_k_strategy.h>
#include <disk/lru_strategy.h>
#include <index/index_factory.h>
#include <io/executor.h>
#include <plan/physical/builder.h>
#include <sstream>
#include <table/column.h>
using namespace beedb;
Database::Database(Config &config, const std::string &file_name)
: _config(config), _storage_manager(file_name), _buffer_manager(config[Config::k_BufferFrames], _storage_manager),
_table_disk_manager(_buffer_manager)
{
// Initialize BufferManagerStrategy.
std::unique_ptr<disk::BufferReplacementStrategy> replacement_strategy{};
if (config[Config::k_BufferReplacementStrategy] == Config::LFU)
{
replacement_strategy.reset(new disk::LFUStrategy());
}
else if (config[Config::k_BufferReplacementStrategy] == Config::LRU_K)
{
replacement_strategy.reset(new disk::LRUKStrategy(config[Config::k_LRU_K]));
}
else
{
replacement_strategy.reset(new disk::LRUStrategy());
}
this->_buffer_manager.replacement_strategy(std::move(replacement_strategy));
}
Database::~Database()
{
// Update statistics
for (auto [_, table] : this->_tables)
{
if (table->is_virtual() == false)
{
this->persist_table_statistics(table, this->_statistics.table_statistics().cardinality(*table));
}
}
// Delete tables AFTER all statistics are persisted.
// Otherwise it is possible to delete the statistics table
// before all updates are done.
for (auto [_, table] : this->_tables)
{
delete table;
}
}
void Database::boot()
{
// Initialize tables with fixed schema and allocate pages for the data,
// if the file is empty.
this->initialize_database(this->_storage_manager.count_pages() == 0);
// Read all tables, columns and indices and build tables from the results.
auto tables_executor = io::Executor{*this};
tables_executor.execute(io::Query{"select * from system_tables"}, [&](const table::Tuple &table_tuple) {
const auto table_id = table_tuple.get(0).get<std::int32_t>();
const auto table_name = table_tuple.get(1).get<std::string>();
const auto table_page = table_tuple.get(2).get<std::int32_t>();
auto schema = table::Schema{table_name};
auto columns_executor = io::Executor{*this};
columns_executor.execute(
io::Query{"select * from system_columns where table_id = " + std::to_string(table_id)},
[&](const table::Tuple &column_tuple) {
const auto column_id = column_tuple.get(0).get<std::int32_t>();
const auto column_type_id = column_tuple.get(2).get<std::int32_t>();
const auto column_length = column_tuple.get(3).get<std::int32_t>();
const auto column_name = column_tuple.get(4).get<std::string>();
const auto column_is_nullable = column_tuple.get(5).get<std::int32_t>();
const auto type =
table::Type(static_cast<table::Type::Id>(column_type_id), std::uint16_t(column_length));
std::vector<std::shared_ptr<index::IndexInterface>> indices;
auto indices_executor = io::Executor{*this};
indices_executor.execute(
io::Query{"select * from system_indices where column_id = " + std::to_string(column_id)},
[&](const table::Tuple &index_tuple) {
const auto index_id = index_tuple.get(0).get<std::int32_t>();
const auto index_type_id = index_tuple.get(2).get<std::int32_t>();
const auto index_name = index_tuple.get(3).get<std::string>();
const auto is_unique = index_tuple.get(4).get<std::int32_t>();
indices.push_back(index::IndexFactory::new_index(
index_name, static_cast<index::Type>(index_type_id), static_cast<bool>(is_unique)));
this->_next_index_id = std::max(index_id + 1u, this->_next_index_id);
});
schema.add({column_id, type, static_cast<bool>(column_is_nullable), std::move(indices)},
{column_name, table_name});
this->_next_column_id = std::max(column_id + 1u, this->_next_column_id);
});
this->_tables[table_name] = new table::Table(table_id, table_page, std::move(schema));
auto statistics_executor = io::Executor{*this};
statistics_executor.execute(
{"select * from system_table_statistics where table_id = " + std::to_string(table_id)},
[this, table_id](const table::Tuple &tuple) {
const auto cardinality = tuple.get(1).get<std::int64_t>();
this->_statistics.table_statistics().cardinality(table_id, cardinality);
});
this->_next_table_id = std::max(table_id + 1u, this->_next_table_id);
});
// Build and fill all indices.
io::Executor build_index_executor{*this};
for (auto &[table_name, table] : this->_tables)
{
for (auto i = 0u; i < table->schema().size(); i++)
{
const auto &column = table->schema().column(i);
const auto &attribute = table->schema().attribute(i);
for (auto index : column.indices())
{
auto plan = plan::physical::Builder::build_index_plan(*this, table_name, attribute.name, index->name());
build_index_executor.execute(plan);
}
}
}
}
void Database::initialize_database(const bool create_schema)
{
if (create_schema)
{
// Allocate page for tables.
auto tables_page = this->_buffer_manager.allocate();
assert(tables_page->id() == 0);
this->_buffer_manager.unpin(tables_page, false);
// Allocate page for columns.
auto columns_page = this->_buffer_manager.allocate();
assert(columns_page->id() == 1);
this->_buffer_manager.unpin(columns_page, false);
// Allocate page for indices.
auto indices_page = this->_buffer_manager.allocate();
assert(indices_page->id() == 2);
this->_buffer_manager.unpin(indices_page, false);
// Allocate page for indices.
auto table_statistics_page = this->_buffer_manager.allocate();
assert(table_statistics_page->id() == 3);
this->_buffer_manager.unpin(table_statistics_page, false);
}
std::string tables_name("system_tables");
table::Schema tables_schema{tables_name};
tables_schema.add({table::Type::INT, false}, {"id", tables_schema.table_name()});
tables_schema.add({{table::Type::CHAR, 48}, false}, {"name", tables_schema.table_name()});
tables_schema.add({table::Type::INT, false}, {"page", tables_schema.table_name()});
auto tables_table = new table::Table(-1, 0, std::move(tables_schema));
std::string columns_name("system_columns");
table::Schema columns_schema{columns_name};
columns_schema.add({table::Type::INT, false}, {"id", columns_schema.table_name()});
columns_schema.add({table::Type::INT, false}, {"table_id", columns_schema.table_name()});
columns_schema.add({table::Type::INT, false}, {"type_id", columns_schema.table_name()});
columns_schema.add({table::Type::INT, false}, {"length", columns_schema.table_name()});
columns_schema.add({{table::Type::CHAR, 48}, false}, {"name", columns_schema.table_name()});
columns_schema.add({table::Type::INT, false}, {"is_nullable", columns_schema.table_name()});
columns_schema.add({table::Type::INT, false}, {"is_unique", columns_schema.table_name()});
columns_schema.add({table::Type::INT, false}, {"is_primary_key", columns_schema.table_name()});
auto columns_table = new table::Table(-1, 1, std::move(columns_schema));
std::string indices_name("system_indices");
table::Schema indices_schema{indices_name};
indices_schema.add({table::Type::INT, false}, {"id", indices_schema.table_name()});
indices_schema.add({table::Type::INT, false}, {"column_id", indices_schema.table_name()});
indices_schema.add({table::Type::INT, false}, {"type_id", indices_schema.table_name()});
indices_schema.add({{table::Type::CHAR, 48}, false}, {"name", indices_schema.table_name()});
indices_schema.add({table::Type::INT, false}, {"is_unique", indices_schema.table_name()});
auto indices_table = new table::Table(-1, 2, std::move(indices_schema));
std::string table_statistics_name("system_table_statistics");
table::Schema table_statistics_schema{table_statistics_name};
table_statistics_schema.add({table::Type::INT, false}, {"table_id", table_statistics_schema.table_name()});
table_statistics_schema.add({table::Type::LONG, false}, {"cardinality", table_statistics_schema.table_name()});
auto table_statistics_table = new table::Table(-1, 3, std::move(table_statistics_schema));
this->_tables[tables_table->name()] = tables_table;
this->_tables[columns_table->name()] = columns_table;
this->_tables[indices_table->name()] = indices_table;
this->_tables[table_statistics_table->name()] = table_statistics_table;
}
void Database::create_table(const table::Schema &schema)
{
auto tables_table = this->_tables["system_tables"];
auto columns_table = this->_tables["system_columns"];
auto table_statistics_table = this->_tables["system_table_statistics"];
// Persist table.
table::Tuple table_tuple(tables_table->schema(), tables_table->schema().row_size());
auto table_id = std::int32_t(this->_next_table_id++);
auto name = schema.table_name();
auto page = this->_buffer_manager.allocate();
auto page_id = std::int32_t(page->id());
this->_buffer_manager.unpin(page, false);
table_tuple.set(0, table_id);
table_tuple.set(1, name);
table_tuple.set(2, page_id);
this->_table_disk_manager.add_row(*tables_table, std::move(table_tuple));
// Persist columns
for (auto i = 0u; i < schema.size(); i++)
{
const auto &column = schema.column(i);
const auto &attribute = schema.attribute(i);
table::Tuple column_tuple(columns_table->schema(), columns_table->schema().row_size());
auto column_id = std::int32_t(this->_next_column_id++);
auto column_name = attribute.name;
auto type_id = std::int32_t(static_cast<table::Type::Id>(column.type()));
auto length = std::int32_t(column.type().dynamic_length());
auto is_nullable = std::int32_t(column.is_nullable());
auto is_unique = std::int32_t(0);
auto is_primary_key = std::int32_t(0);
column_tuple.set(0, column_id);
column_tuple.set(1, table_id);
column_tuple.set(2, type_id);
column_tuple.set(3, length);
column_tuple.set(4, column_name);
column_tuple.set(5, is_nullable);
column_tuple.set(6, is_unique);
column_tuple.set(7, is_primary_key);
this->_table_disk_manager.add_row(*columns_table, std::move(column_tuple));
}
table::Tuple table_statistics_tuple(table_statistics_table->schema(), table_statistics_table->schema().row_size());
auto cardinality = std::int64_t{0};
table_statistics_tuple.set(0, table_id);
table_statistics_tuple.set(1, cardinality);
this->_table_disk_manager.add_row(*table_statistics_table, std::move(table_statistics_tuple));
this->_tables[schema.table_name()] = new table::Table(table_id, page_id, schema);
}
void Database::create_index(const table::Column &column, const index::Type type, const std::string &name,
const bool is_unique)
{
auto *indices_table = this->_tables["system_indices"];
table::Tuple tuple(indices_table->schema(), indices_table->schema().row_size());
auto index_id = std::int32_t(this->_next_index_id++);
auto column_id = std::int32_t(column.id());
auto type_id = std::int32_t(type);
auto index_name = name;
auto unique = std::int32_t(is_unique);
tuple.set(0, index_id);
tuple.set(1, column_id);
tuple.set(2, type_id);
tuple.set(3, index_name);
tuple.set(4, unique);
this->_table_disk_manager.add_row(*indices_table, std::move(tuple));
}
void Database::persist_table_statistics(beedb::table::Table *table, const std::uint64_t cardinality)
{
io::Executor executor(*this);
executor.execute({"update system_table_statistics set cardinality = " + std::to_string(std::int64_t(cardinality)) +
" where table_id = " + std::to_string(table->id()) + ";"});
}

150
src/disk/buffer_manager.cpp Normal file
View File

@ -0,0 +1,150 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <algorithm>
#include <cassert>
#include <cstring>
#include <disk/buffer_manager.h>
#include <exception/disk_exception.h>
#include <limits>
using namespace beedb::disk;
BufferManager::BufferManager(const std::size_t count_frames, StorageManager &space_manager,
std::unique_ptr<BufferReplacementStrategy> replacement_strategy)
: _space_manager(space_manager), _replacement_strategy(std::move(replacement_strategy)), _frames(count_frames),
_frame_information(count_frames)
{
}
BufferManager::~BufferManager()
{
// Check no frame is pinned anymore (this would indicate programming failure).
for (const auto &frame_information : this->_frame_information)
{
assert(frame_information.is_pinned() == false && "Not all pages are unpinned on shutdown.");
}
// Write all dirty pages back to disk.
this->flush();
}
Page *BufferManager::pin(const Page::page_id page_id)
{
this->_pin_sequence++;
auto frame_information_iterator = this->frame_information(page_id);
const bool is_frame_buffered = frame_information_iterator != this->_frame_information.end();
if (is_frame_buffered)
{
// Update frame information.
(*frame_information_iterator).increase_pin_count(this->_pin_sequence);
const auto index = std::distance(this->_frame_information.begin(), frame_information_iterator);
return reinterpret_cast<Page *>(&(this->_frames[index]));
}
else
{
// Find frame for the pinned page.
const auto frame_index = this->find_frame();
if (this->_frame_information[frame_index].is_pinned())
{
throw exception::EvictedPagePinnedException(frame_index);
}
// Write frame back, if the data was modified.
if (this->_frame_information[frame_index].is_dirty() == true)
{
this->_space_manager.write(reinterpret_cast<Page &>(this->_frames[frame_index]));
}
// Load page into frame.
const auto page = this->_space_manager.read(page_id);
auto *frame = &(this->_frames[frame_index]);
std::memcpy(frame, &page, sizeof(Page));
// Clear frame information.
this->_frame_information[frame_index].occupy(page.id(), this->_pin_sequence);
this->_evicted_frames++;
return reinterpret_cast<Page *>(frame);
}
}
void BufferManager::unpin(const Page::page_id page_id, const bool is_dirty)
{
auto frame_information_iterator = this->frame_information(page_id);
if (frame_information_iterator != this->_frame_information.end())
{
auto &frame_information = *frame_information_iterator;
if (frame_information.pin_count() < 1)
{
throw exception::PageWasNotPinnedException(page_id);
}
frame_information.decrease_pin_count();
frame_information.is_dirty(frame_information.is_dirty() | is_dirty);
}
}
Page *BufferManager::allocate()
{
const auto page_id = this->_space_manager.allocate();
return this->pin(page_id);
}
void BufferManager::flush()
{
for (auto i = 0u; i < this->_frame_information.size(); i++)
{
auto &frame_information = this->_frame_information[i];
// Write back, when the frame is dirty.
if (frame_information.is_occupied() && frame_information.is_dirty())
{
auto &page = reinterpret_cast<Page &>(this->_frames[i]);
assert(page.id() == frame_information.page_id());
this->_space_manager.write(page);
this->_frame_information[i].is_dirty(false);
}
}
}
std::vector<beedb::disk::FrameInformation>::iterator BufferManager::frame_information(const Page::page_id page_id)
{
return std::find_if(this->_frame_information.begin(), this->_frame_information.end(),
[page_id](const FrameInformation &info) { return info.page_id() == page_id; });
}
std::size_t BufferManager::find_frame()
{
// Check buffer for not occupied pages.
for (auto index = 0u; index < this->_frames.size(); index++)
{
if (this->_frame_information[index].is_occupied() == false)
{
return index;
}
}
// If no free buffer frame found, replace an occupied one.
return this->_replacement_strategy->find_victim(this->_frame_information);
}

57
src/disk/lfu_strategy.cpp Normal file
View File

@ -0,0 +1,57 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <disk/lfu_strategy.h>
#include <exception/disk_exception.h>
using namespace beedb::disk;
std::size_t LFUStrategy::find_victim(const std::vector<FrameInformation> &frame_information)
{
/**
* Assignment (1): Implement the Least Frequently Used eviction strategy.
*
* This strategy evicts that frame from the frame buffer which
* has no pins and is pinned the least times.
*
* This function returns the index of the frame that should be evicted.
*
* Hints for implementation:
* - The Parameter "frame_information" is a list of information about
* all frames and their current states.
* - You can get the information for the frame i by "frame_information[i]".
* - The information offers a method "is_pinned()" that returns true, when
* the frame is pinned at the moment, false otherwise.
* - The information offers a method "count_all_pins()" that returns the number
* of all pins (not only active pins). The number is will be reset on eviction.
*
* Procedure:
* - Scan the frame_information for frames that are not pinned at the moment.
* - Select the frame with the lowest number of all pins.
* - Return the index of that frame.
*/
std::size_t evict_index = 0u;
return evict_index;
}

View File

@ -0,0 +1,65 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <disk/lru_k_strategy.h>
#include <exception/disk_exception.h>
using namespace beedb::disk;
std::size_t LRUKStrategy::find_victim(const std::vector<FrameInformation> &frame_information)
{
/**
* Assignment (1): Implement the Least Recently Used eviction strategy with regard
* to the last "k" pins.
*
* The normal "LRU" strategy is a special case of this strategy,
* using k = 1: LRU == LRU-1
*
* The LRU-K strategy takes not just the last reference of a frame into account,
* but the k-th last reference. For more details, take a look into the original
* paper for LRU-K: "The LRU-K page replacement algorithm for database disk buffering".
*
* This function returns the index of the frame that should be evicted.
*
* Hints for implementation:
* - The Parameter "frame_information" is a list of information about
* all frames and their current states.
* - The method "this->k()" returns the parameter "k" for this strategy.
* - You can get the information for the frame i by "frame_information[i]".
* - The information offers a method "is_pinned()" that returns true, when
* the frame is pinned at the moment, false otherwise.
* - "frame_information[i].pin_timestamp(j)" returns the e j-th timestamp a
* query pinned the frame "i".
*
* Procedure:
* - Scan the frame_information for frames that are not pinned at the moment
* and have a (1) overall number of pins lesser than k or (2) greater equal number of pins.
* - If (1) is not empty: Select the frame with the lowest timestamp of the last pin.
* - Otherwise select the frame with the lowest timestamp of the last k pins from (2).
* - Return the index to that frame.
*/
std::size_t evict_index = 0u;
return evict_index;
}

57
src/disk/lru_strategy.cpp Normal file
View File

@ -0,0 +1,57 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <disk/lru_strategy.h>
#include <exception/disk_exception.h>
using namespace beedb::disk;
std::size_t LRUStrategy::find_victim(const std::vector<FrameInformation> &frame_information)
{
/**
* Assignment (1): Implement the Least Recently Used eviction strategy.
*
* This strategy evicts that frame from the frame buffer which
* is not pinned at the moment and is pinned lately.
*
* This function returns the index of the frame that should be evicted.
*
* Hints for implementation:
* - The Parameter "frame_information" is a list of information about
* all frames and their current states.
* - You can get the information for the frame i by "frame_information[i]".
* - The information offers a method "is_pinned()" that returns true, when
* the frame is pinned at the moment, false otherwise.
* - "frame_information[i].last_pin_timestamp()" returns the timestamp of the last time a
* query pinned the frame "i".
*
* Procedure:
* - Scan the frame_information for frames that are not pinned at the moment.
* - Select the frame with the lowest timestamp of the last pin.
* - Return the index of that frame.
*/
std::size_t evict_index = 0u;
return evict_index;
}

View File

@ -0,0 +1,75 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <cassert>
#include <config.h>
#include <disk/storage_manager.h>
#include <exception/disk_exception.h>
using namespace beedb::disk;
StorageManager::StorageManager(const std::string &file_name)
{
this->_storage_file.open(file_name, std::ios::in | std::ios::out | std::ios::binary);
if (this->_storage_file.is_open() == false)
{
// Create file if not exists. Non-existing files can not be opened with in | out only -> add trunc.
this->_storage_file.open(file_name, std::ios::in | std::ios::out | std::ios::binary | std::ios::trunc);
}
if (this->_storage_file.is_open() == false)
{
throw exception::CanNotOpenStorageFile();
}
this->_storage_file.seekg(0, std::ios::end);
assert(this->_storage_file.tellg() % Config::page_size == 0);
this->_count_pages = this->_storage_file.tellg() / Config::page_size;
assert(sizeof(Page) == Config::page_size);
}
StorageManager::~StorageManager()
{
this->_storage_file.close();
}
Page StorageManager::read(const Page::page_id page_id)
{
Page page(page_id);
this->_storage_file.seekg(page.id() * sizeof(Page), std::ios::beg);
this->_storage_file.read(reinterpret_cast<char *>(&page), sizeof(Page));
return page;
}
void StorageManager::write(Page &page)
{
this->_storage_file.seekp(page.id() * sizeof(Page), std::ios::beg);
this->_storage_file.write(reinterpret_cast<char *>(&page), sizeof(Page));
}
Page::page_id StorageManager::allocate()
{
Page page(this->_count_pages++);
this->write(page);
return page.id();
}

View File

@ -0,0 +1,64 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/add_to_index_operator.h>
using namespace beedb::execution;
AddToIndexOperator::AddToIndexOperator(const std::uint32_t column_index,
const std::shared_ptr<index::IndexInterface> index)
: _column_index(column_index), _index(index)
{
}
void AddToIndexOperator::open()
{
this->child()->open();
}
void AddToIndexOperator::close()
{
this->child()->close();
}
beedb::util::optional<beedb::table::Tuple> AddToIndexOperator::next()
{
auto next = this->child()->next();
if (next == true)
{
if (next->page_id() != disk::Page::INVALID_PAGE_ID)
{
const auto &column = next->schema().column(this->_column_index);
if (column == table::Type::INT)
{
this->_index->put(std::get<std::int32_t>(next->get(this->_column_index).value()), next->page_id());
}
else if (column == table::Type::LONG)
{
this->_index->put(std::get<std::int64_t>(next->get(this->_column_index).value()), next->page_id());
}
}
return next;
}
return {};
}

View File

@ -0,0 +1,220 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
//#include <execution/aggregate_operator.h>
//#include <exception/column_not_grouped_exception.h>
//#include <expression/attribute.h>
//
// using namespace beedb::execution;
//
// AggregateOperator::AggregateOperator(const table::Schema& schema,
// const std::vector<expression::Attribute> &groups,
// const std::vector<expression::Attribute> &columns)
// : AbstractOperator(schema),_groups(groups), _columns(columns)
//{
//}
//
// void AggregateOperator::initialize()
//{
//
// /// TODO: Output schema is going to be generated outside of operators!
//
//// const auto& child_schema = this->child<AbstractOperator>(0)->schema();
//
//// for(auto i = 0u; i < child_schema.size(); i++) {
//// const auto& child_column = child_schema[i];
//// const auto& child_name = child_column.name();
//// const auto& child_table_name = child<AbstractOperator>(0)->table_name();
//// for(const auto &column : this->_columns) {
//// if(child_table_name == column.table_alias() && child_name == column.column_name()) {
//// if(column.is_aggregation()) {
//// this->_schema.add({this->aggregation_column_type(column.aggregation_type(),
/// child_column.type()), child_name}, child_table_name); / const auto index = this->_schema.size() -
/// 1; / this->_schema_index_aggregation_map[index] = column.aggregation_type(); /
/// this->_schema_index_map[index] = i; / this->_aggregation_indices.push_back(index); / break; / } /
///} / }
//
//// for(const auto &column : this->_groups) {
//// if(child_table_name == column.table_alias() && child_name == column.column_name()) {
//// this->_schema.add(child_column, child_table_name);
//// break;
//// }
//// }
//// }
//}
//
// beedb::table::Type AggregateOperator::aggregation_column_type(const beedb::expression::AttributeOrigin aggregation,
// const beedb::table::Type &column_type)
//{
// if(aggregation == beedb::expression::AttributeOrigin::AGG_COUNT) {
// return table::Type::LONG;
// } else if(aggregation == beedb::expression::AttributeOrigin::AGG_AVG) {
// return table::Type::FLOAT;
// } else {
// return column_type;
// }
//}
//
// std::vector<beedb::table::Tuple> AggregateOperator::execute()
//{
// std::vector<table::Tuple> input_tuples = this->child<OperatorAtATimeInterface>(0)->execute();
// if(input_tuples.empty() && this->_aggregated) {
// return {};
// }
// this->_aggregated = true;
//
// Aggregator aggregator;
// std::vector<table::Tuple> output_tuples;
//
// if(this->_groups.empty()) {
// table::Tuple tuple(this->_schema, this->_schema.row_size());
// for(const auto index : this->_aggregation_indices) {
// const auto aggregate_function = this->_schema_index_aggregation_map[index];
// const auto source_index = this->_schema_index_map[index];
// if(aggregate_function == beedb::expression::AttributeOrigin::AGG_AVG) {
// aggregator.avg(input_tuples, source_index, tuple, index);
// } else if(aggregate_function == beedb::expression::AttributeOrigin::AGG_MIN) {
// aggregator.min(input_tuples, source_index, tuple, index);
// } else if(aggregate_function == beedb::expression::AttributeOrigin::AGG_MAX) {
// aggregator.max(input_tuples, source_index, tuple, index);
// } else if(aggregate_function == beedb::expression::AttributeOrigin::AGG_SUM) {
// aggregator.sum(input_tuples, source_index, tuple, index);
// } else if(aggregate_function == beedb::expression::AttributeOrigin::AGG_COUNT) {
// aggregator.count(input_tuples, tuple, index);
// }
// }
// output_tuples.push_back(std::move(tuple));
// } else {
// std::vector<std::uint32_t> indices;
// std::unordered_map<std::size_t, std::vector<table::Tuple>> hash_aggregation;
// for(auto& tuple : input_tuples) {
// const auto hash = this->hash(indices, tuple);
// hash_aggregation[hash].push_back(table::Tuple(tuple.schema(), std::move(tuple)));
// }
//
// output_tuples.reserve(hash_aggregation.size());
// const auto row_size = this->_schema.row_size();
// for(auto& [_, input_tuples] : hash_aggregation) {
// table::Tuple out_tuple(this->_schema, row_size);
// for(const auto index : this->_aggregation_indices) {
// const auto aggregate_function = this->_schema_index_aggregation_map[index];
// const auto source_index = this->_schema_index_map[index];
// if(aggregate_function == expression::AttributeOrigin::AGG_AVG) {
// aggregator.avg(input_tuples, source_index, out_tuple, index);
// } else if(aggregate_function == expression::AttributeOrigin::AGG_MIN) {
// aggregator.min(input_tuples, source_index, out_tuple, index);
// } else if(aggregate_function == expression::AttributeOrigin::AGG_MAX) {
// aggregator.max(input_tuples, source_index, out_tuple, index);
// } else if(aggregate_function == expression::AttributeOrigin::AGG_SUM) {
// aggregator.sum(input_tuples, source_index, out_tuple, index);
// } else if(aggregate_function == expression::AttributeOrigin::AGG_COUNT) {
// aggregator.count(input_tuples, out_tuple, index);
// }
// }
// output_tuples.push_back(std::move(out_tuple));
// }
// }
//
// return output_tuples;
//}
//
// void Aggregator::avg(const std::vector<table::Tuple> &source_tuples, const std::size_t source_index, table::Tuple
// &target_tuple, const std::size_t target_index)
//{
// if(source_tuples.empty()) {
// return;
// }
//
// auto source_type = source_tuples[0].schema()[source_index].type();
// table::Value sum { source_type, 0 };
// for(const auto& tuple : source_tuples) {
// sum += tuple.get(source_index);
// }
//
// float avg;
// if(sum == table::Type::LONG) {
// avg = sum.get<std::int64_t>() / float(source_tuples.size());
// } else if(sum == table::Type::INT) {
// avg = sum.get<std::int32_t>() / float(source_tuples.size());
// } else if(sum == table::Type::FLOAT) {
// avg = sum.get<float>() / float(source_tuples.size());
// } else if(sum == table::Type::DOUBLE) {
// avg = sum.get<double>() / float(source_tuples.size());
// }
//
// target_tuple.set(target_index, avg);
//}
//
// void Aggregator::min(const std::vector<table::Tuple> &source_tuples, const std::size_t source_index, table::Tuple
// &target_tuple, const std::size_t target_index)
//{
// auto max_value = target_tuple.get(target_index).max();
// target_tuple.set(target_index, max_value);
//
// for(const auto& tuple : source_tuples) {
// auto v = tuple.get(source_index);
// if(v < target_tuple.get(target_index)) {
// target_tuple.set(target_index, v);
// }
// }
//}
//
// void Aggregator::max(const std::vector<table::Tuple> &source_tuples, const std::size_t source_index, table::Tuple
// &target_tuple, const std::size_t target_index)
//{
// auto min_value = target_tuple.get(target_index).min();
// target_tuple.set(target_index, min_value);
//
// for(const auto& tuple : source_tuples) {
// auto v = tuple.get(source_index);
// if(v > target_tuple.get(target_index)) {
// target_tuple.set(target_index, v);
// }
// }
//}
//
// void Aggregator::sum(const std::vector<table::Tuple> &source_tuples, const std::size_t source_index, table::Tuple
// &target_tuple, const std::size_t target_index)
//{
// auto sum = target_tuple.get(target_index);
// for(const auto& tuple : source_tuples) {
// sum += tuple.get(source_index);
// }
// target_tuple.set(target_index, sum);
//}
//
// void Aggregator::count(const std::vector<table::Tuple> &source_tuples, table::Tuple &target_tuple, const std::size_t
// target_index)
//{
// auto result = target_tuple.get(target_index).get<std::int64_t>() + std::int64_t(source_tuples.size());
// target_tuple.set(target_index, result);
//}
//
// std::size_t AggregateOperator::hash(const std::vector<std::uint32_t> &group_indices,
// const beedb::table::Tuple &tuple)
//{
// std::size_t h = 0u;
// for(const auto index : group_indices) {
// h += std::hash<table::Value>()(tuple.get(index));
// }
// return std::hash<std::size_t>()(h);
//}

View File

@ -0,0 +1,36 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <cstring>
#include <execution/binary_operator.h>
using namespace beedb::execution;
beedb::table::Tuple BinaryOperator::combine(const table::Schema &new_schema, const beedb::table::Tuple &left,
const beedb::table::Tuple &right) const
{
auto tuple = table::Tuple{new_schema, new_schema.row_size()};
std::memcpy(tuple.data(), left.data(), left.schema().row_size());
std::memcpy(tuple.data() + left.schema().row_size(), right.data(), right.schema().row_size());
return tuple;
}

View File

@ -0,0 +1,84 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/build_index_operator.h>
using namespace beedb::execution;
BuildIndexOperator::BuildIndexOperator(Database &database, const std::string &table_name,
const table::Schema::ColumnIndexType column_index, const std::string &index_name)
: _database(database), _table_name(table_name), _column_index(column_index), _index_name(index_name)
{
}
void BuildIndexOperator::open()
{
if (this->left_child() != nullptr)
{
this->left_child()->open();
}
this->right_child()->open();
}
void BuildIndexOperator::close()
{
if (this->left_child() != nullptr)
{
this->left_child()->close();
}
this->right_child()->close();
}
beedb::util::optional<beedb::table::Tuple> BuildIndexOperator::next()
{
if (this->left_child() != nullptr)
{
this->left_child()->next();
}
auto *table = this->_database.table(this->_table_name);
const auto &column_to_index = table->schema().column(this->_column_index);
auto index = column_to_index.index(this->_index_name);
auto tuple_to_index = this->right_child()->next();
while (tuple_to_index == true)
{
if (tuple_to_index->page_id() != disk::Page::INVALID_PAGE_ID)
{
if (column_to_index == table::Type::INT)
{
index->put(std::get<std::int32_t>(tuple_to_index->get(this->_column_index).value()),
tuple_to_index->page_id());
}
else if (column_to_index == table::Type::LONG)
{
index->put(std::get<std::int64_t>(tuple_to_index->get(this->_column_index).value()),
tuple_to_index->page_id());
}
}
tuple_to_index = this->right_child()->next();
}
return {};
}

View File

@ -0,0 +1,49 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/create_index_operator.h>
#include <index/index_factory.h>
using namespace beedb::execution;
CreateIndexOperator::CreateIndexOperator(Database &database, const std::string &table_name,
const expression::Attribute &attribute, const std::string &index_name,
const bool is_unique, const index::Type type)
: _database(database), _table_name(table_name), _attribute(attribute), _index_name(index_name),
_is_unique(is_unique), _index_type(type)
{
}
beedb::util::optional<beedb::table::Tuple> CreateIndexOperator::next()
{
auto *table = this->_database[this->_table_name];
auto &column = (*table)[this->_attribute];
// Persist index
this->_database.create_index(column, this->_index_type, this->_index_name, this->_is_unique);
// Create index
auto index = index::IndexFactory::new_index(this->_index_name, this->_index_type, this->_is_unique);
column.add_index(std::move(index));
return {};
}

View File

@ -0,0 +1,36 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/create_table_operator.h>
using namespace beedb::execution;
CreateTableOperator::CreateTableOperator(beedb::Database &database, const table::Schema schema_to_create)
: _database(database), _schema_to_create(schema_to_create)
{
}
beedb::util::optional<beedb::table::Tuple> CreateTableOperator::next()
{
this->_database.create_table(this->_schema_to_create);
return {};
}

View File

@ -0,0 +1,65 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/cross_product_operator.h>
using namespace beedb::execution;
CrossProductOperator::CrossProductOperator(const table::Schema &&schema) : _schema(schema)
{
}
void CrossProductOperator::open()
{
this->left_child()->open();
this->right_child()->open();
this->_next_left_tuple = this->left_child()->next();
}
void CrossProductOperator::close()
{
this->left_child()->close();
this->right_child()->close();
}
beedb::util::optional<beedb::table::Tuple> CrossProductOperator::next()
{
if (this->_next_left_tuple == false)
{
return {};
}
while (this->_next_left_tuple == true)
{
auto next_right_tuple = this->right_child()->next();
if (next_right_tuple == true)
{
return {this->combine(this->_schema, this->_next_left_tuple, next_right_tuple)};
}
this->right_child()->close();
this->right_child()->open();
this->_next_left_tuple = this->left_child()->next();
}
return {};
}

View File

@ -0,0 +1,144 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/hash_join_operator.h>
using namespace beedb::execution;
HashJoinOperator::HashJoinOperator(const table::Schema schema, const std::uint32_t left_index,
const std::uint32_t right_index)
: _schema(schema), _left_index(left_index), _right_index(right_index), _hash_table(_left_index)
{
}
void HashJoinOperator::build_hash_table()
{
/**
* Assignment (4): Implement the HashJoin operator
*
* The hash join will join from to sources by hashing one and probing
* the other.
*
* This function builds the hash table by scanning and hashing all
* tuples from the left child.
*
* Hints for implementation:
* - The methods "this->left_child()" and "this->right_child()"
* grant access to both children of the operator.
* - Each operator has a "next()" method, which returns the next
* tuple from that operator. But, that tuple may be empty (when
* there is no tuple to return).
* - You can test whether the a tuple is not empty with "tuple == true".
* - You can add a tuple to the hash table by "this->_hash_table.put(tuple)".
*
* Procedure:
* - Iterate over the left child and add them into the hash table.
*/
}
beedb::util::optional<beedb::table::Tuple> HashJoinOperator::probe_hash_table()
{
/**
* Assignment (4): Implement the HashJoin operator
*
* The hash join will join from to sources by hashing one and probing
* the other.
*
* This function probes the built hash table and returns the next
* tuple matching the join condition.
*
* Hints for implementation:
* - The methods "this->left_child()" and "this->right_child()"
* grant access to both children of the operator.
* - Each operator has a "next()" method, which returns the next
* tuple from that operator. But, that tuple may be empty (when
* there is no tuple to return).
* - You can test whether the a tuple is not empty with "tuple == true".
* - Each tuple has a "get(i)" method which returns the value of
* the tuple at index "i".
* - The required indices for joining the left and the right child
* are stored in "this->_left_index" and "this->_right_index".
* - You can test whether the hash table contains a candidate for a
* value by "this->_hash_table.contains(value)".
* - You can get all matching tuples from the hash table by
* "this->_hash_table.get(value)" which returns a reference
* to a vector containing the tuples.
* - You can combine two tuples using the combine method
* "this->combine(this->_schema, tuple_1, tuple_2)", which produces
* a new tuple.
* - Because of one match may create more than one tuple, but you can
* only return one tuple, you have to buffer the tuples created by
* a single match.
* - For buffering tuples, you can use the TupleBuffer ("this->_tuple_buffer").
* - You can add tuples to the buffer by "this->_tuple_buffer.add(tuple)".
* - You can get the next tuple from the buffer by "this->_tuple_buffer.pop".
*
* Procedure:
* - Iterate over the right child.
* - For every tuple, check whether the build hash table
* contains tuples that matches. Remember: The key for the hash table is
* a value at the index "this->_right_index" of a tuple from the right child.
* - For every tuple from the right child and all tuples stored in the hash table
* create a new tuple use "this->combine(tuple_1, tuple_2)".
* - Add all new created tuples to the tuple buffer.
* - Return the first tuple from the buffer by "popping" it.
*/
return {};
}
void HashJoinOperator::open()
{
this->left_child()->open();
this->right_child()->open();
}
void HashJoinOperator::close()
{
this->left_child()->close();
this->right_child()->close();
}
beedb::util::optional<beedb::table::Tuple> HashJoinOperator::next()
{
// Build phase
if (this->_is_built == false)
{
this->build_hash_table();
this->_is_built = true;
}
// In case there are tuple in the buffer, return them first.
if (this->_tuple_buffer.empty() == false)
{
return {this->_tuple_buffer.pop()};
}
else
{
this->_tuple_buffer.clear();
}
// Probe phase
return this->probe_hash_table();
}

View File

@ -0,0 +1,152 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/index_scan_operator.h>
#include <index/non_unique_index_interface.h>
#include <index/range_index_interface.h>
#include <index/unique_index_interface.h>
using namespace beedb::execution;
IndexScanOperator::IndexScanOperator(const std::uint32_t scan_page_limit, const beedb::table::Schema &schema,
beedb::disk::BufferManager &buffer_manager,
beedb::table::TableDiskManager &table_disk_manager, std::set<KeyRange> &key_ranges,
std::shared_ptr<index::IndexInterface> index)
: _scan_page_limit(scan_page_limit), _schema(schema), _buffer_manager(buffer_manager),
_table_disk_manager(table_disk_manager), _key_ranges(std::move(key_ranges)), _index(index)
{
}
void IndexScanOperator::open()
{
for (const auto &key_range : this->_key_ranges)
{
if (key_range.is_single_key())
{
if (this->_index->is_unique())
{
const auto page =
dynamic_cast<index::UniqueIndexInterface *>(this->_index.get())->get(key_range.single_key());
if (page.has_value())
{
this->_pages_to_scan.push(page.value());
}
}
else
{
const auto pages =
dynamic_cast<index::NonUniqueIndexInterface *>(this->_index.get())->get(key_range.single_key());
if (pages.has_value())
{
for (const auto page : pages.value())
{
this->_pages_to_scan.push(page);
}
}
}
}
else
{
const auto pages =
dynamic_cast<index::RangeIndexInterface *>(this->_index.get())->get(key_range.from(), key_range.to());
if (pages.has_value())
{
for (const auto page : pages.value())
{
this->_pages_to_scan.push(page);
}
}
}
}
}
void IndexScanOperator::close()
{
if (this->_pinned_pages.empty() == false)
{
for (const auto page_id : this->_pinned_pages)
{
this->_buffer_manager.unpin(page_id, false);
}
this->_pinned_pages.clear();
}
}
beedb::util::optional<beedb::table::Tuple> IndexScanOperator::next()
{
if (this->_buffer.empty() == false)
{
auto next = this->_buffer.pop();
return {std::move(next)};
}
this->_buffer.clear();
if (this->_pinned_pages.empty() == false)
{
for (const auto page_id : this->_pinned_pages)
{
this->_buffer_manager.unpin(page_id, false);
}
this->_pinned_pages.clear();
}
if (this->_pages_to_scan.empty())
{
return {};
}
// When we need more, scan pages max pages.
for (auto i = 0u; i < this->_scan_page_limit; i++)
{
if (this->_pages_to_scan.empty())
{
break;
}
auto next_page_id = this->_pages_to_scan.front();
this->_pages_to_scan.pop();
auto page = this->_buffer_manager.pin(next_page_id);
auto tuples = this->_table_disk_manager.read_rows(page, this->_schema);
if (tuples.empty() == false)
{
this->_buffer.add(tuples);
this->_pinned_pages.push_back(page->id());
}
else
{
this->_buffer_manager.unpin(page, false);
break;
}
}
if (this->_buffer.empty() == false)
{
auto next = this->_buffer.pop();
return {std::move(next)};
}
else
{
return {};
}
}

View File

@ -0,0 +1,62 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/insert_operator.h>
using namespace beedb::execution;
InsertOperator::InsertOperator(beedb::disk::BufferManager &buffer_manager,
beedb::table::TableDiskManager &table_disk_manager,
beedb::statistic::SystemStatistics &statistics, beedb::table::Table &table)
: _buffer_manager(buffer_manager), _table_disk_manager(table_disk_manager), _statistics(statistics), _table(table)
{
}
void InsertOperator::open()
{
this->child()->open();
}
void InsertOperator::close()
{
this->child()->close();
}
beedb::util::optional<beedb::table::Tuple> InsertOperator::next()
{
if (this->_last_pinned_page != disk::Page::INVALID_PAGE_ID)
{
this->_buffer_manager.unpin(this->_last_pinned_page, true);
this->_last_pinned_page = disk::Page::INVALID_PAGE_ID;
}
auto next = this->child()->next();
if (next == true)
{
auto tuple = this->_table_disk_manager.add_row(this->_table, this->_table.schema(), std::move(next.value()));
this->_last_pinned_page = tuple.page_id();
this->_statistics.table_statistics().add_cardinality(this->_table, 1);
return {std::move(tuple)};
}
return {};
}

View File

@ -0,0 +1,80 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/limit_operator.h>
using namespace beedb::execution;
LimitOperator::LimitOperator(const beedb::table::Schema &schema, const std::uint64_t limit, const std::uint64_t offset)
: _schema(schema), _limit(limit), _offset(offset)
{
}
void LimitOperator::open()
{
this->child()->open();
}
void LimitOperator::close()
{
this->child()->close();
}
beedb::util::optional<beedb::table::Tuple> LimitOperator::next()
{
/**
* Assignment (3): Implement the operator "LIMIT"
*
* The limit operator reduces the number of tuples by the query.
* Limit takes two inputs: The overall number of tuples, that should be
* produced by the query ond the offset. The latter one is an optional
* parameter, which is set to zero by default.
*
* This function returns a tuple or no tuple each time the
* parent operator calls the next() function.
*
* Hints for implementation:
* - The limit and the offset are accessible by
* "this->_limit" and "this->_offset".
* - You can return "no tuple" by "return { };"
* - You can ask the child operator for the next tuple by
* "this->child()->next()" which is an optional tuple that
* may contain a tuple or not.
* - You can ask the optional tuple if it has a value with
* "tuple->has_value()".
* - The type "beedb::util::optional" is inspired by std::optional,
* take a look to https://en.cppreference.com/w/cpp/utility/optional
*
*
* Procedure:
* - The first time this function is called skip "this->_offset"
* tuples.
* - Ask the child operator for the next tuple and return it until
* you reached the limit.
* - When the limit is reached (you have to count by yourself)
* or the tuple from children has no value, return (also)
* no tuple (by "return {};").
*/
return {};
}

View File

@ -0,0 +1,117 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/nested_loops_join_operator.h>
using namespace beedb::execution;
NestedLoopsJoinOperator::NestedLoopsJoinOperator(const table::Schema &&schema,
std::unique_ptr<PredicateMatcherInterface> predicate_matcher)
: _schema(schema), _predicate_matcher(std::move(predicate_matcher))
{
}
void NestedLoopsJoinOperator::open()
{
/**
* Assignment (4): Implement the NestedLoopsJoin operator
*
* The nested loops join will join from to sources by two loops.
* The outer loop will iterate over the left child, the inner loop
* will iterate over the right child to combine all matching tuples.
*
* This function opens the operator.
*
* Hints for implementation:
* - The methods "this->left_child()" and "this->right_child()"
* grant access to both children of the operator.
* - Each operator has an "open()" method.
* - Each operator has a "next()" method, which returns the next
* tuple from that operator.
*
* Procedure:
* - Open both children.
* - Store the first next tuple from the left child. You can store it
* in "this->_next_left_tuple".
*/
}
void NestedLoopsJoinOperator::close()
{
/**
* Assignment (4): Implement the NestedLoopsJoin operator
*
* The nested loops join will join from to sources by two loops.
* The outer loop will iterate over the left child, the inner loop
* will iterate over the right child to combine all matching tuples.
*
* This function closes the operator.
*
* Hints for implementation:
* - The methods "this->left_child()" and "this->right_child()"
* grant access to both children of the operator.
* - Each operator has an "close()" method.
*
* Procedure:
* - Close both children.
*/
}
beedb::util::optional<beedb::table::Tuple> NestedLoopsJoinOperator::next()
{
/**
* Assignment (4): Implement the NestedLoopsJoin operator
*
* The nested loops join will join from to sources by two loops.
* The outer loop will iterate over the left child, the inner loop
* will iterate over the right child to combine all matching tuples.
*
* This function return the next tuple produced by this operator.
*
* Hints for implementation:
* - The methods "this->left_child()" and "this->right_child()"
* grant access to both children of the operator.
* - Each operator has a "next()" method, which returns the next
* tuple from that operator.
* - "this->_next_left_tuple" stores the next tuple from the left child.
* - You can test whether the a tuple holds a value with "tuple == true",
* e.g. "this->_next_left_tuple == true".
* - You can test whether two tuples matches the join condition using
* "this->matches(tuple_1, tuple_2)" which may return true or false.
* - You can combine two tuples using the combine method
* "this->combine(this->_schema, tuple_1, tuple_2)", which produces
* a new tuple.
*
* Procedure:
* - Iterate over the left child and store the next tuple in "this->_next_left_tuple".
* - Iterate over the right child until you found a tuple that matches the
* join condition for the next left and right tuple.
* - Produce and return a new tuple by combining the two matching tuples.
* - After each inner iteration close and open the right child to start
* at the first tuple of the right child.
*/
return {};
}

View File

@ -0,0 +1,72 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/order_operator.h>
#include <util/quicksort.h>
using namespace beedb::execution;
OrderOperator::OrderOperator(const beedb::table::Schema &schema,
std::vector<std::pair<std::uint32_t, bool>> &&order_columns)
: _schema(schema), _order_columns(order_columns)
{
}
void OrderOperator::open()
{
this->child()->open();
}
void OrderOperator::close()
{
this->child()->close();
}
beedb::util::optional<beedb::table::Tuple> OrderOperator::next()
{
if (this->_result_table == nullptr)
{
this->_result_table.reset(new table::MemoryTable(this->_schema));
auto tuple = this->child()->next();
while (tuple == true)
{
this->_result_table->copy_to_memory(tuple);
tuple = this->child()->next();
}
if (this->_result_table->empty())
{
return {};
}
auto comparator = TupleComparator{this->_order_columns};
util::Quicksort::sort(this->_result_table->tuples(), comparator);
}
if (this->_stack_index < this->_result_table->size())
{
auto &next_tuple = this->_result_table->tuples()[this->_stack_index++];
return {std::move(next_tuple)};
}
return {};
}

View File

@ -0,0 +1,50 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/projection_operator.h>
using namespace beedb::execution;
ProjectionOperator::ProjectionOperator(const table::Schema schema) : _schema(schema)
{
}
void ProjectionOperator::open()
{
this->child()->open();
}
void ProjectionOperator::close()
{
this->child()->close();
}
beedb::util::optional<beedb::table::Tuple> ProjectionOperator::next()
{
auto next_tuple = this->child()->next();
if (next_tuple == true)
{
return {table::Tuple(this->_schema, std::move(next_tuple.value()))};
}
return {};
}

View File

@ -0,0 +1,56 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/selection_operator.h>
using namespace beedb::execution;
SelectionOperator::SelectionOperator(const table::Schema &schema,
std::unique_ptr<PredicateMatcherInterface> predicate_matcher)
: _schema(schema), _predicate_matcher(std::move(predicate_matcher))
{
}
void SelectionOperator::open()
{
this->child()->open();
}
void SelectionOperator::close()
{
this->child()->close();
}
beedb::util::optional<beedb::table::Tuple> SelectionOperator::next()
{
auto tuple = this->child()->next();
while (tuple == true)
{
if (this->matches(tuple))
{
return tuple;
}
tuple = this->child()->next();
}
return {};
}

View File

@ -0,0 +1,112 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/sequential_scan_operator.h>
using namespace beedb::execution;
SequentialScanOperator::SequentialScanOperator(const std::uint32_t scan_page_limit, const beedb::table::Schema &schema,
beedb::disk::BufferManager &buffer_manager,
beedb::table::TableDiskManager &table_disk_manager,
const beedb::table::Table &table)
: _scan_page_limit(scan_page_limit), _schema(schema), _buffer_manager(buffer_manager),
_table_disk_manager(table_disk_manager), _table(table)
{
}
void SequentialScanOperator::open()
{
this->_next_page_id_to_scan = this->_table.page_id();
}
void SequentialScanOperator::close()
{
if (this->_pinned_pages.empty() == false)
{
for (const auto page_id : this->_pinned_pages)
{
this->_buffer_manager.unpin(page_id, false);
}
this->_pinned_pages.clear();
}
}
beedb::util::optional<beedb::table::Tuple> SequentialScanOperator::next()
{
if (this->_buffer.empty() == false)
{
auto next = this->_buffer.pop();
return {std::move(next)};
}
this->_buffer.clear();
if (this->_pinned_pages.empty() == false)
{
for (const auto page_id : this->_pinned_pages)
{
this->_buffer_manager.unpin(page_id, false);
}
this->_pinned_pages.clear();
}
if (this->_next_page_id_to_scan == disk::Page::INVALID_PAGE_ID)
{
return {};
}
// When we need more, scan pages max pages.
for (auto i = 0u; i < this->_scan_page_limit; i++)
{
if (this->_next_page_id_to_scan == disk::Page::INVALID_PAGE_ID)
{
break;
}
auto page = this->_buffer_manager.pin(this->_next_page_id_to_scan);
auto tuples = this->_table_disk_manager.read_rows(page, this->_schema);
if (tuples.empty() == false)
{
this->_buffer.add(tuples);
this->_pinned_pages.push_back(page->id());
}
else
{
this->_buffer_manager.unpin(page, false);
this->_next_page_id_to_scan = disk::Page::INVALID_PAGE_ID;
break;
}
this->_next_page_id_to_scan = page->next_page_id();
}
if (this->_buffer.empty() == false)
{
auto next = this->_buffer.pop();
return {std::move(next)};
}
else
{
return {};
}
}

View File

@ -0,0 +1,39 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/tuple_buffer_operator.h>
using namespace beedb::execution;
TupleBufferOperator::TupleBufferOperator(const beedb::table::Schema schema) : _schema(schema)
{
}
beedb::util::optional<beedb::table::Tuple> TupleBufferOperator::next()
{
if (this->_tuple_buffer.empty() == false)
{
return {this->_tuple_buffer.pop()};
}
return {};
}

View File

@ -0,0 +1,51 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <execution/update_operator.h>
using namespace beedb::execution;
void UpdateOperator::open()
{
this->child()->open();
}
void UpdateOperator::close()
{
this->child()->close();
}
beedb::util::optional<beedb::table::Tuple> UpdateOperator::next()
{
auto next = this->child()->next();
while (next == true)
{
for (const auto &update : this->_new_column_values)
{
next->set(update.first, update.second);
}
this->_table_disk_manager.update_row(next);
next = this->child()->next();
}
return {};
}

View File

@ -0,0 +1,31 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <expression/attribute.h>
namespace beedb::expression
{
std::ostream &operator<<(std::ostream &stream, const Attribute &attribute)
{
return stream << attribute.combined_name;
}
} // namespace beedb::expression

View File

@ -0,0 +1,95 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include <expression/predicate.h>
using namespace beedb::expression;
beedb::expression::Attributes PredicateAnalyzer::attributes(const Predicate &predicate)
{
Attributes attributes;
if (std::holds_alternative<std::unique_ptr<LogicalConnective>>(predicate))
{
const auto &connective = std::get<std::unique_ptr<LogicalConnective>>(predicate);
auto left_attributes = PredicateAnalyzer::attributes(connective->left);
auto right_attributes = PredicateAnalyzer::attributes(connective->right);
for (const auto &attr : left_attributes)
{
attributes.push_back(attr);
}
for (const auto &attr : right_attributes)
{
attributes.push_back(attr);
}
}
else if (std::holds_alternative<std::unique_ptr<Atom>>(predicate))
{
const auto &atom = std::get<std::unique_ptr<Atom>>(predicate);
if (std::holds_alternative<Attribute>(atom->left))
{
attributes.push_back(std::get<Attribute>(atom->left));
}
if (std::holds_alternative<Attribute>(atom->right))
{
attributes.push_back(std::get<Attribute>(atom->right));
}
}
return attributes;
}
bool PredicateAnalyzer::contains_range_predicate(const Predicate &predicate)
{
if (std::holds_alternative<std::unique_ptr<LogicalConnective>>(predicate))
{
const auto &connective = std::get<std::unique_ptr<LogicalConnective>>(predicate);
return PredicateAnalyzer::contains_range_predicate(connective->left) ||
PredicateAnalyzer::contains_range_predicate(connective->right);
}
else if (std::holds_alternative<std::unique_ptr<Atom>>(predicate))
{
const auto &atom = std::get<std::unique_ptr<Atom>>(predicate);
auto atom_ptr = atom.get();
return (typeid(*atom_ptr) == typeid(expression::EQ) || typeid(*atom_ptr) == typeid(expression::NEQ)) == false;
}
return false;
}
bool PredicateAnalyzer::contains_not_equals_predicate(const Predicate &predicate)
{
if (std::holds_alternative<std::unique_ptr<LogicalConnective>>(predicate))
{
const auto &connective = std::get<std::unique_ptr<LogicalConnective>>(predicate);
return PredicateAnalyzer::contains_not_equals_predicate(connective->left) ||
PredicateAnalyzer::contains_not_equals_predicate(connective->right);
}
else if (std::holds_alternative<std::unique_ptr<Atom>>(predicate))
{
const auto &atom = std::get<std::unique_ptr<Atom>>(predicate);
auto atom_ptr = atom.get();
return typeid(*atom_ptr) == typeid(expression::NEQ);
}
return false;
}

View File

@ -0,0 +1,98 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <cassert>
#include <cstdint>
namespace beedb::compression
{
class WAHBitVector
{
public:
WAHBitVector() : _is_literal_word(0), _content(0)
{
}
~WAHBitVector() = default;
inline bool is_fill() const
{
return _is_literal_word == 0;
}
inline bool is_literal() const
{
return _is_literal_word;
}
inline void is_fill(bool is_fill)
{
_is_literal_word = !is_fill;
}
inline bool fill_bit() const
{
return _content >> 30;
}
inline void fill_bit(const bool fill_bit)
{
_content = (fill_bit << 30) | count();
}
inline std::uint32_t count() const
{
return _content & 0x3FFFFFFF;
}
WAHBitVector &operator++()
{
_content = (count() + 1) | (fill_bit() << 30);
return *this;
}
WAHBitVector operator++(int)
{
WAHBitVector copy(*this);
++(*this);
return copy;
}
inline void set(const std::size_t index, const bool bit)
{
assert(index >= 0 && index <= 31);
_content ^= (-bit ^ _content) & (1UL << index);
}
inline bool get(const std::size_t index) const
{
assert(index >= 0 && index <= 31);
return (_content >> index) & 1U;
}
inline void clear()
{
_content = 0;
}
private:
std::uint32_t _is_literal_word : 1, _content : 31;
} __attribute__((packed));
} // namespace beedb::compression

182
src/include/config.h Normal file
View File

@ -0,0 +1,182 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <cassert>
#include <cstdint>
#include <exception/config_exception.h>
#include <iostream>
#include <string>
#include <unordered_map>
namespace beedb
{
/**
* Holds all configuration for the DBMS.
*/
class Config
{
public:
using ConfigKey = std::string;
using ConfigValue = std::int32_t; // TODO: consider renaming this or the struct below...?
///// COMPILE TIME OPTIONS - CHANGES REQUIRE REBUILDING
static constexpr std::uint16_t page_size = 4096;
static constexpr std::uint16_t b_plus_tree_page_size = 1024;
public:
// defining constants and other values, for convenience and ease-of-reading
enum BufferReplacementStrategy
{
LRU,
LRU_K,
LFU
};
// important key's for non-string based notation:
static constexpr auto k_PageSize = "page_size";
static constexpr auto k_BPlusTreePageSize = "b_plus_tree_page_size";
static constexpr auto k_ScanPageLimit = "scan_page_limit";
static constexpr auto k_BufferFrames = "buffer_frames";
static constexpr auto k_BufferReplacementStrategy = "buffer_replacement_strategy";
static constexpr auto k_LRU_K = "lru_k";
static constexpr auto k_CheckFinalPlan = "check_final_plan";
static constexpr auto k_OptimizationEnableHashJoin = "enable_hash_join";
static constexpr auto k_OptimizationEnableIndexScan = "enable_index_scan";
static constexpr auto k_OptimizationDisableOptimization = "no_optimization";
static constexpr auto k_PrintExecutionStatistics = "print_execution_statistics";
// this object represents a ConfigValue in the map and stores some meta information
struct ConfigMapValue
{
ConfigValue value;
bool is_mutable = true;
bool requires_restart = false;
operator ConfigValue() const
{
return value;
}
operator bool() const
{
return value != 0u;
}
operator BufferReplacementStrategy()
{
return static_cast<BufferReplacementStrategy>(value);
}
static constexpr bool immutable = false;
};
Config()
{
// for transparency, we make compile-time options available in the config map (read only)
_configuration.insert({k_PageSize, {page_size, ConfigMapValue::immutable}});
_configuration.insert({k_BPlusTreePageSize, {b_plus_tree_page_size, ConfigMapValue::immutable}});
}
~Config() = default; // TODO: persist changes in config
/**
* @brief operator [] Read only access to values of the Configuration!
*
* This method is identical to get.
*
* @param key
* @return
*/
ConfigMapValue operator[](const ConfigKey &key) const
{
if (_configuration.find(key) == _configuration.end())
{
throw exception::ConfigException(key);
}
return _configuration.at(key);
}
ConfigMapValue get(const ConfigKey &key) const
{
return this->operator[](key);
}
/**
* @brief set sets a configuration value. Can override existing values, if the flag ConfigMapValue.is_mutable is not
* set!
* @param key a new or existing key
* @param value the new value
* @param is_mutable defaults to true
* @param requires_restart defaults to false. currently unused.
* @return the input value, returned from the map
*/
ConfigMapValue set(ConfigKey key, ConfigValue value, bool is_mutable = true, bool requires_restart = false)
{
if (_configuration.find(key) != _configuration.end())
{
// if this key already exists, check if it is read only
if (!_configuration[key].is_mutable)
{
throw exception::CanNotModifyAtRuntimeException(key);
}
}
// // TODO implement: persist config map on shutdown and uncomment this
// if (_configuration[key].requires_restart) {
// std::cout << "Note: " << "This option requires a restart of the application to take effect!"
// << std::endl;
// }
return _configuration[key] = {value, is_mutable, requires_restart};
}
bool contains(ConfigKey key) const
{
return _configuration.find(key) != _configuration.end();
}
operator std::string()
{
std::string str("");
str += "Current Configuration:\n";
for (const auto &[k, value] : _configuration)
{
str += "";
str += std::to_string(value.value);
// str += ", " + (value.is_mutable ? std::string("r/w") : std::string("r") );
str += "\t<- " + k + (!value.is_mutable ? " (immutable)" : "") + "\n";
}
return str;
}
private:
using ConfigurationMap = std::unordered_map<ConfigKey, ConfigMapValue>;
// holds the actual configuration values
ConfigurationMap _configuration;
};
} // namespace beedb

181
src/include/database.h Normal file
View File

@ -0,0 +1,181 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <config.h>
#include <cstdint>
#include <disk/buffer_manager.h>
#include <disk/lru_strategy.h>
#include <disk/page.h>
#include <disk/storage_manager.h>
#include <functional>
#include <index/type.h>
#include <statistic/system_statistics.h>
#include <string>
#include <table/table.h>
#include <table/table_disk_manager.h>
#include <table/tuple.h>
#include <unordered_map>
#include <utility>
namespace beedb
{
class Database
{
public:
Database(Config &config, const std::string &file_name);
~Database();
/**
* Boots the database management system.
* During the boot, all persisted tables, their schemas and indices
* will be loaded to memory.
* All indices will be filled with data from disk.
*/
void boot();
/**
* @return Instance of the TableDiskManager.
*/
inline table::TableDiskManager &table_disk_manager()
{
return _table_disk_manager;
}
/**
* @return Instance of the BufferManager.
*/
inline disk::BufferManager &buffer_manager()
{
return _buffer_manager;
}
/**
* @return Immutable instance of the config.
*/
inline const Config &config() const
{
return _config;
}
/**
* @return Mutable instance of the config.
*/
inline Config &config()
{
return _config;
}
inline statistic::SystemStatistics &system_statistics()
{
return _statistics;
}
/**
* Checks whether a table exists.
*
* @param name Name of the table.
* @return True, if the table exists.
*/
inline bool table_exists(const std::string &name)
{
return _tables.find(name) != _tables.end();
}
/**
* Returns a pointer to the requested table.
*
* @param name Name of the requested table.
* @return Pointer to the table.
*/
table::Table *table(const std::string &name)
{
if (table_exists(name))
{
return _tables[name];
}
return nullptr;
}
table::Table *operator[](const std::string &table_name)
{
return table(table_name);
}
const table::Table &operator[](const std::string &table_name) const
{
// unchecked, const access to tables
return *(_tables.at(table_name));
}
/**
* Creates a table with a given schema.
* The table will be persisted and available after creation.
*
* @param schema Schema for the table.
*/
void create_table(const table::Schema &schema);
/**
* Creates an index for a specific column.
* The index will be persisted, filled, and available after creation.
*
* @param column Column to be indexed.
* @param type Type of the index.
* @param name Name of the index.
* @param is_unique True, when the index is a unique index.
*/
void create_index(const table::Column &column, const index::Type type, const std::string &name,
const bool is_unique);
private:
Config &_config;
disk::StorageManager _storage_manager;
disk::BufferManager _buffer_manager;
table::TableDiskManager _table_disk_manager;
std::unordered_map<std::string, table::Table *> _tables;
std::uint32_t _next_table_id = 1;
std::uint32_t _next_column_id = 1;
std::uint32_t _next_index_id = 1;
statistic::SystemStatistics _statistics;
/**
* Initializes the database. When the database is empty,
* we will create a new database schema containing all meta tables.
*
* @param create_schema True, when a database schema should be created.
*/
void initialize_database(const bool create_schema);
/**
* Persists the table statistics.
*
* @param table Table
* @param cardinality Cardinality
*/
void persist_table_statistics(table::Table *table, const std::uint64_t cardinality);
};
} // namespace beedb

View File

@ -0,0 +1,144 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "buffer_replacement_strategy.h"
#include "frame.h"
#include "page.h"
#include "storage_manager.h"
#include <cstdint>
#include <memory>
#include <vector>
namespace beedb::disk
{
/**
* The BufferManager buffers pages stored on the disk in memory.
* Since the system has not infinite memory, the number of buffered
* pages (named "frames") is limited.
*
* Every access to a page on the disk is done by pinning the page
* through the BufferManager. When the page is not needed any more
* (e.g. all tuples are scanned), the page can be unpinned by the
* BufferManager.
*/
class BufferManager
{
public:
BufferManager(const std::size_t count_frames, StorageManager &space_manager,
std::unique_ptr<BufferReplacementStrategy> replacement_strategy = nullptr);
~BufferManager();
/**
* Loads the page from disk into memory and returns a pointer
* to the page. When the page is still buffered, the page will
* not be loaded twice, but guaranteed to stay in memory until
* it is unpinned.
*
* @param page_id Id of the page.
* @return Pointer to the page, that allows accessing the data.
*/
Page *pin(const Page::page_id page_id);
/**
* Notifies the BufferManager that the page is not needed anymore.
* In case no one needs the page, the frame can be used for other
* pages buffered from disk in memory.
*
* @param page_id Id of the page.
* @param is_dirty True, when the content of the page was modified.
*/
void unpin(const Page::page_id page_id, const bool is_dirty);
/**
* Notifies the BufferManager that the page is not needed anymore.
* In case no one needs the page, the frame can be used for other
* pages buffered from disk in memory.
*
* @param page_id Id of the page.
* @param is_dirty True, when the content of the page was modified.
*/
inline void unpin(Page *page, const bool is_dirty)
{
unpin(page->id(), is_dirty);
}
/**
* Allocates a new page on the disk and loads the page to memory.
*
* @return Pointer to the pinned(!) page.
*/
Page *allocate();
/**
* Set the replacement strategy which picks frames to be replaced,
* when all frames are occupied, but a new page is requested to
* be loaded from disk to memory.
* @param replacement_strategy
*/
inline void replacement_strategy(std::unique_ptr<BufferReplacementStrategy> replacement_strategy)
{
_replacement_strategy = std::move(replacement_strategy);
}
/**
* @return Number of evicted frames.
*/
inline std::size_t evicted_frames() const
{
return _evicted_frames;
}
private:
StorageManager &_space_manager;
std::unique_ptr<BufferReplacementStrategy> _replacement_strategy;
std::vector<Frame> _frames;
std::vector<FrameInformation> _frame_information;
std::size_t _pin_sequence = 0u;
std::size_t _evicted_frames = 0u;
/**
* Writes all dirty pages from memory to disk.
*/
void flush();
/**
* Lookup for frame information for a specific page.
* The frame information stores information like pin
* history, pinned page for a frame.
*
* @param page_id Id of the page.
* @return An iterator to the frame information or end() if the frame was not found.
*/
std::vector<FrameInformation>::iterator frame_information(const Page::page_id page_id);
/**
* Find a frame which should be occupied for a new page request.
* The target frame can be a) a free frame or b) a frame holding
* another, not pinned page.
*
* @return Index for the frame
*/
std::size_t find_frame();
};
} // namespace beedb::disk

View File

@ -0,0 +1,47 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "frame.h"
#include <vector>
namespace beedb::disk
{
/**
* The BufferReplacementStrategy decides which frame should
* be re-used for a new page, when no free frame is available.
*/
class BufferReplacementStrategy
{
public:
virtual ~BufferReplacementStrategy() = default;
/**
* Picks a frame that holds a unused page and should be
* replaced by a new page, requested by a query.
*
* @param frame_information Information of all frames.
* @return Index of the frame, that should be used for a new page.
*/
virtual std::size_t find_victim(const std::vector<FrameInformation> &frame_information) = 0;
};
} // namespace beedb::disk

164
src/include/disk/frame.h Normal file
View File

@ -0,0 +1,164 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "page.h"
#include <cstddef>
#include <limits>
#include <vector>
namespace beedb::disk
{
/**
* Storage for a page that is loaded from disk to memory.
*/
using Frame = std::array<std::byte, sizeof(Page)>;
/**
* Stores information about a frame that holds a page
* in memory.
* Information are:
* - The id of the current page hold by the frame
* - Number of pins
* - Dirty bit; if set, the page has to be written back
* to disk when the page is replaced.
* - History of pin timestamps
*/
class FrameInformation
{
public:
FrameInformation() = default;
~FrameInformation() = default;
void occupy(const Page::page_id page_id, const std::size_t timestamp)
{
this->_page_id = page_id;
this->_pin_count = 1u;
this->_is_dirty = false;
this->_pin_timestamps.clear();
this->_pin_timestamps.push_back(timestamp);
}
/**
* @return Id of the occupied page.
*/
Page::page_id page_id() const
{
return _page_id;
}
/**
* @return True, if the frame is occupied by a page.
*/
bool is_occupied() const
{
return _page_id != Page::INVALID_PAGE_ID;
}
/**
* @return Number of active pins.
*/
std::size_t pin_count() const
{
return _pin_count;
}
/**
* @return True, if the frame is pinned at the moment.
*/
bool is_pinned() const
{
return _pin_count > 0u;
}
/**
* Increases the pin count and adds the timestamp to history.
* @param timestamp Timestamp of the pin.
*/
void increase_pin_count(const std::size_t timestamp)
{
_pin_count++;
_pin_timestamps.push_back(timestamp);
}
/**
* Decreases the pin count.
*/
void decrease_pin_count()
{
_pin_count--;
}
/**
* @return True, if the frame is dirty ergo the content
* of the page was modified.
*/
bool is_dirty() const
{
return _is_dirty;
}
/**
* Update the dirty flag.
* @param is_dirty
*/
void is_dirty(const bool is_dirty)
{
_is_dirty = is_dirty;
}
/**
* @return Timestamp of the last pin.
*/
std::size_t last_pin_timestamp() const
{
if (_pin_timestamps.empty())
{
return std::numeric_limits<std::size_t>::max();
}
return _pin_timestamps.back();
}
/**
* @return Timestamp of the i-th pin.
*/
std::size_t pin_timestamp(const std::size_t i) const
{
return _pin_timestamps[i];
}
/**
* @return Number of how many times the frame was pinned.
*/
std::size_t count_all_pins() const
{
return _pin_timestamps.size();
}
private:
Page::page_id _page_id = Page::INVALID_PAGE_ID;
std::size_t _pin_count = 0u;
bool _is_dirty = false;
std::vector<std::size_t> _pin_timestamps;
};
} // namespace beedb::disk

View File

@ -0,0 +1,38 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "buffer_replacement_strategy.h"
namespace beedb::disk
{
/**
* Replaces the last frequently used frame.
*/
class LFUStrategy final : public BufferReplacementStrategy
{
public:
LFUStrategy() = default;
virtual ~LFUStrategy() = default;
virtual std::size_t find_victim(const std::vector<FrameInformation> &frame_information);
};
} // namespace beedb::disk

View File

@ -0,0 +1,46 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "buffer_replacement_strategy.h"
#include <list>
namespace beedb::disk
{
class LRUKStrategy final : public BufferReplacementStrategy
{
public:
LRUKStrategy(const std::size_t k) : _k(k)
{
}
virtual ~LRUKStrategy() = default;
virtual std::size_t find_victim(const std::vector<FrameInformation> &frame_information);
private:
const std::size_t _k = 0;
std::size_t k() const
{
return _k;
}
};
} // namespace beedb::disk

View File

@ -0,0 +1,38 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "buffer_replacement_strategy.h"
namespace beedb::disk
{
/**
* Replaces the last recently used frame.
*/
class LRUStrategy final : public BufferReplacementStrategy
{
public:
LRUStrategy() = default;
virtual ~LRUStrategy() = default;
virtual std::size_t find_victim(const std::vector<FrameInformation> &frame_information);
};
} // namespace beedb::disk

172
src/include/disk/page.h Normal file
View File

@ -0,0 +1,172 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <array>
#include <config.h>
#include <cstdint>
#include <cstring>
#include <iostream>
namespace beedb::disk
{
/**
* Represents a page on disk, holding a header for meta information
* and raw memory for storing data.
* Pages can be linked logically. All linked pages contain data for the
* same table; like a linked list of storage.
*/
class Page
{
public:
using page_id = std::uint64_t;
using page_offset = std::uint16_t;
static constexpr page_id INVALID_PAGE_ID = std::numeric_limits<Page::page_id>::max();
static constexpr page_offset INVALID_PAGE_OFFSET = std::numeric_limits<Page::page_offset>::max();
private:
/**
* Stores meta information for a page.
*/
struct Header
{
Page::page_id page_id = INVALID_PAGE_ID;
Page::page_id next_page_id = INVALID_PAGE_ID;
Page::page_offset last_written_index = 0u;
std::byte padding[8];
} __attribute__((packed));
public:
static constexpr std::size_t data_size = Config::page_size - sizeof(Header);
Page(const page_id id) : _data({std::byte{'\0'}})
{
_header.page_id = id;
}
~Page() = default;
/**
* @return Id of this page.
*/
inline page_id id() const
{
return _header.page_id;
}
/**
* @return Id of the page which is logical connected to this page.
*/
inline page_id next_page_id() const
{
return _header.next_page_id;
}
/**
* Updates the next page id.
* @param next_page_id Id of the next page.
*/
inline void next_page_id(const page_id next_page_id)
{
_header.next_page_id = next_page_id;
}
/**
* @return True, when this page has a next page.
*/
inline bool has_next_page() const
{
return next_page_id() != INVALID_PAGE_ID;
}
/**
* @return Number of bytes actually written to this page.
*/
inline Page::page_offset size() const
{
return _header.last_written_index;
}
/**
* @return Number of free bytes.
*/
inline Page::page_offset free_space() const
{
return _data.size() - size();
}
/**
* @return Pointer to the data stored on this page.
*/
inline std::byte *data()
{
return _data.data();
}
/**
* Replaces content on the page.
*
* @param begin First byte to write.
* @param data Pointer to the data to be written.
* @param length Length of the data.
*/
inline void overwrite(const Page::page_offset begin, const std::byte *data, const Page::page_offset length)
{
std::memcpy(&_data[begin], data, length);
}
/**
* Adds new content at the current end of the page.
* @param data Pointer to the data.
* @param length Length of the data.
* @return First byte the data was written to.
*/
inline std::size_t append(const std::byte *data, const Page::page_offset length)
{
const auto begin = _header.last_written_index;
_header.last_written_index = begin + length;
overwrite(begin, data, length);
return begin;
}
/**
* @return True, when this is a persisted page.
*/
operator bool() const
{
return _header.page_id < INVALID_PAGE_ID;
}
/**
* @param index Index of data.
* @return Pointer to the data.
*/
std::byte *operator[](const Page::page_offset index)
{
return &_data[index];
}
private:
Header _header;
std::array<std::byte, Page::data_size> _data;
} __attribute__((packed));
} // namespace beedb::disk

View File

@ -0,0 +1,75 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "page.h"
#include <cstdint>
#include <fstream>
#include <string>
namespace beedb::disk
{
/**
* The StorageManager grants access to the data written to the disk.
*/
class StorageManager
{
public:
StorageManager(const std::string &file_name);
~StorageManager();
/**
* Copy a page from disk to memory.
*
* @param page_id Id of the page.
* @return Data, now copied to memory.
*/
Page read(const Page::page_id page_id);
/**
* Write the page from memory to disk.
*
* @param page Page to be written.
*/
void write(Page &page);
/**
* Allocates a new page in the disk file and extends the
* file by the new allocated page.
*
* @return Id of the new allocated page.
*/
Page::page_id allocate();
/**
* @return Number of pages stored in the disk file.
*/
inline std::size_t count_pages() const
{
return _count_pages;
}
private:
std::size_t _count_pages = 0u;
std::fstream _storage_file;
};
} // namespace beedb::disk

View File

@ -0,0 +1,86 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <exception>
#include <string>
namespace beedb::exception
{
class CommandException : public std::exception
{
public:
CommandException(const std::string &message) : _message(message)
{
}
~CommandException() = default;
virtual const char *what() const noexcept
{
return _message.c_str();
}
private:
const std::string _message;
};
class UnknownCommandException final : public CommandException
{
public:
UnknownCommandException(const std::string &command) : CommandException("Unknown command '" + command + "'.")
{
}
UnknownCommandException() : UnknownCommandException("Unknown command")
{
}
virtual ~UnknownCommandException() = default;
};
class CommandSyntaxException final : public CommandException
{
public:
CommandSyntaxException(const std::string &command, const std::string &syntax_hint)
: CommandException("Command syntax exception '" + command + "'.\n" + syntax_hint)
{
}
CommandSyntaxException() : CommandException("Command syntax exception")
{
}
virtual ~CommandSyntaxException() = default;
};
class UnknownCommandInputException final : public CommandException
{
public:
UnknownCommandInputException(const std::string &input) : CommandException("Not supported input '" + input + "'")
{
}
virtual ~UnknownCommandInputException() = default;
};
} // namespace beedb::exception

View File

@ -0,0 +1,59 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "exception.h"
#include <string>
namespace beedb::exception
{
class ConfigException : public DatabaseException
{
public:
ConfigException(const std::string &message) : DatabaseException(DatabaseException::Configuration, message)
{
}
virtual ~ConfigException() = default;
};
class KeyNotFoundException final : public ConfigException
{
public:
KeyNotFoundException(const std::string &key) : ConfigException("Option " + key + " not found.")
{
}
virtual ~KeyNotFoundException() = default;
};
class CanNotModifyAtRuntimeException final : public ConfigException
{
public:
CanNotModifyAtRuntimeException(const std::string &key)
: ConfigException("Option " + key + " can not be changed at runtime.")
{
}
virtual ~CanNotModifyAtRuntimeException() = default;
};
} // namespace beedb::exception

View File

@ -0,0 +1,79 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "exception.h"
#include <string>
namespace beedb::exception
{
class DiskException : public DatabaseException
{
public:
DiskException(const std::string &message) : DatabaseException(DatabaseException::Disk, message)
{
}
virtual ~DiskException() = default;
};
class EvictedPagePinnedException final : public DiskException
{
public:
EvictedPagePinnedException(const std::uint64_t frame_index)
: DiskException("Can not evict page, frame " + std::to_string(frame_index) + " is pinned.")
{
}
virtual ~EvictedPagePinnedException() = default;
};
class PageWasNotPinnedException final : public DiskException
{
public:
PageWasNotPinnedException(const std::uint64_t disk_id)
: DiskException("Page " + std::to_string(disk_id) + " is not pinned, but unpin() called.")
{
}
virtual ~PageWasNotPinnedException() = default;
};
class NoFreeFrameException final : public DiskException
{
public:
NoFreeFrameException() : DiskException("No free frame found for eviction.")
{
}
virtual ~NoFreeFrameException() = default;
};
class CanNotOpenStorageFile final : public DiskException
{
public:
CanNotOpenStorageFile() : DiskException("Can not open storage file.")
{
}
virtual ~CanNotOpenStorageFile() = default;
};
} // namespace beedb::exception

View File

@ -0,0 +1,63 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <exception>
#include <string>
namespace beedb::exception
{
/**
* Generic exception for plan building and execution.
*/
class DatabaseException : public std::exception
{
public:
enum Layer
{
Parser,
LogicalPlan,
Execution,
Index,
Disk,
OutputHandler,
Configuration
};
virtual ~DatabaseException() = default;
virtual const char *what() const noexcept
{
return _message.c_str();
}
protected:
DatabaseException(const Layer layer, const std::string &message) : _layer(layer), _message(message)
{
}
private:
const Layer _layer;
const std::string _message;
};
} // namespace beedb::exception

View File

@ -0,0 +1,48 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "exception.h"
#include <string>
namespace beedb::exception
{
class ExecutionException : public DatabaseException
{
public:
ExecutionException(const std::string &message) : DatabaseException(DatabaseException::Execution, message)
{
}
virtual ~ExecutionException() = default;
};
class NoPhysicalOperatorForNode final : public ExecutionException
{
public:
NoPhysicalOperatorForNode(const std::string &operator_name)
: ExecutionException("Operator " + operator_name + " is not implemented physically.")
{
}
virtual ~NoPhysicalOperatorForNode() = default;
};
} // namespace beedb::exception

View File

@ -0,0 +1,213 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "exception.h"
#include <string>
namespace beedb::exception
{
class LogicalException : public DatabaseException
{
public:
LogicalException(const std::string &message) : DatabaseException(DatabaseException::LogicalPlan, message)
{
}
virtual ~LogicalException() = default;
};
class ColumnCanNotBeNull final : public LogicalException
{
public:
ColumnCanNotBeNull(const std::string &table_name, const std::string &column_name)
: LogicalException("Value for column " + table_name + "." + column_name + " can not be NULL.")
{
}
virtual ~ColumnCanNotBeNull() = default;
};
class ColumnNotFoundException final : public LogicalException
{
public:
ColumnNotFoundException(const std::string &table_name, const std::string &column_name)
: ColumnNotFoundException(table_name + "." + column_name)
{
}
ColumnNotFoundException(const std::string &table_and_column_name)
: LogicalException("Column " + table_and_column_name + " not found.")
{
}
virtual ~ColumnNotFoundException() = default;
};
class ColumnNotGroupedException final : public LogicalException
{
public:
ColumnNotGroupedException(const std::string &table_name, const std::string &column_name)
: LogicalException("Column " + table_name + "." + column_name + " is neither aggregated nor grouped.")
{
}
virtual ~ColumnNotGroupedException() = default;
};
class ColumnNotIndexed final : public LogicalException
{
public:
ColumnNotIndexed(const std::string &table_name, const std::string &column_name)
: LogicalException("Index for " + table_name + "." + column_name + " not found.")
{
}
virtual ~ColumnNotIndexed() = default;
};
class IndexAlreadyExistsException final : public LogicalException
{
public:
IndexAlreadyExistsException(const std::string &table_name, const std::string &column_name)
: LogicalException("Index for " + table_name + "." + column_name + " already exists.")
{
}
virtual ~IndexAlreadyExistsException() = default;
};
class IndexUnsupportedTypeException final : public LogicalException
{
public:
IndexUnsupportedTypeException(const std::string &type_name)
: LogicalException("Type " + type_name + " can not be indexed, Type is unsupported.")
{
}
virtual ~IndexUnsupportedTypeException() = default;
};
class MultipleGroupByException final : public LogicalException
{
public:
MultipleGroupByException() : LogicalException("Only one GROUP BY argument supported!")
{
}
virtual ~MultipleGroupByException() = default;
};
class MultipleTableReferences final : public LogicalException
{
public:
MultipleTableReferences(const std::string &table_name)
: LogicalException("Multiple references to table " + table_name + " without disambiguation.")
{
}
virtual ~MultipleTableReferences() = default;
};
class TableAlreadyExists final : public LogicalException
{
public:
TableAlreadyExists(const std::string &table_name) : LogicalException("Table " + table_name + " already exists.")
{
}
virtual ~TableAlreadyExists() = default;
};
class TableNotFoundException final : public LogicalException
{
public:
TableNotFoundException(const std::string &table_name) : LogicalException("Table " + table_name + " not found.")
{
}
TableNotFoundException(const std::string &table_name, const std::string &reference_name)
: LogicalException("Can not resolve table reference " + table_name + " in statement " + reference_name + ".")
{
}
virtual ~TableNotFoundException() = default;
};
class CanNotResolveColumnException final : public LogicalException
{
public:
CanNotResolveColumnException(const std::string &column_name, const std::string &statement)
: LogicalException("Can not resolve attribute reference " + column_name + " to a table in statement " +
statement + ".")
{
}
CanNotResolveColumnException(const std::string &column_name)
: LogicalException("Can not resolve attribute reference " + column_name + ".")
{
}
virtual ~CanNotResolveColumnException() = default;
};
class NoUniqueReferenceException final : public LogicalException
{
public:
NoUniqueReferenceException(const std::string &attribute_name, const std::string &table1, const std::string &table2)
: LogicalException("Can not uniquely reference attribute " + attribute_name + ". Both table " + table1 +
" and " + table2 + " include this attribute!")
{
}
virtual ~NoUniqueReferenceException() = default;
};
class CanNotCreateTableException final : public LogicalException
{
public:
CanNotCreateTableException() : LogicalException("Can not create table.")
{
}
virtual ~CanNotCreateTableException() = default;
};
class CanNotCreateIndexException final : public LogicalException
{
public:
CanNotCreateIndexException() : LogicalException("Can not create index.")
{
}
virtual ~CanNotCreateIndexException() = default;
};
class CanNotInsertException final : public LogicalException
{
public:
CanNotInsertException() : LogicalException("Can not insert.")
{
}
virtual ~CanNotInsertException() = default;
};
} // namespace beedb::exception

View File

@ -0,0 +1,89 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "exception.h"
#include <string>
namespace beedb::exception
{
class ParserException : public DatabaseException
{
public:
ParserException(const std::string &message) : DatabaseException(DatabaseException::Parser, message)
{
}
virtual ~ParserException() = default;
};
class SqlException final : public ParserException
{
public:
SqlException(const std::string &parser_error, const std::size_t line, const std::size_t column)
: ParserException(parser_error + " in line " + std::to_string(line) + ":" + std::to_string(column) + ".")
{
}
virtual ~SqlException() = default;
};
class UnsupportedStatementException final : public ParserException
{
public:
UnsupportedStatementException(const std::string &statement) : ParserException(statement + " is not supported.")
{
}
virtual ~UnsupportedStatementException() = default;
};
class CanNotConvertNullptrException final : public ParserException
{
public:
CanNotConvertNullptrException() : ParserException("Can not convert nulltptr expression.")
{
}
virtual ~CanNotConvertNullptrException() = default;
};
class UnsupportedOperatorException final : public ParserException
{
public:
UnsupportedOperatorException(const std::string &operator_name)
: ParserException("Unsupported predicate operator: " + operator_name + ".")
{
}
virtual ~UnsupportedOperatorException() = default;
};
class UnsupportedColumnType final : public ParserException
{
public:
UnsupportedColumnType() : ParserException("Unsupported column type.")
{
}
virtual ~UnsupportedColumnType() = default;
};
} // namespace beedb::exception

View File

@ -0,0 +1,54 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "unary_operator.h"
#include <index/index_interface.h>
#include <memory>
namespace beedb::execution
{
/**
* Operator for adding tuples to an existing index.
*/
class AddToIndexOperator final : public UnaryOperator
{
public:
AddToIndexOperator(const std::uint32_t column_index, const std::shared_ptr<index::IndexInterface> index);
virtual ~AddToIndexOperator() = default;
virtual void open();
virtual util::optional<table::Tuple> next();
virtual void close();
virtual const table::Schema &schema() const
{
return _schema;
};
private:
table::Schema _schema;
const std::uint32_t _column_index;
const std::shared_ptr<index::IndexInterface> _index;
};
} // namespace beedb::execution

View File

@ -0,0 +1,67 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
//#pragma once
//
//#include "abstract_operator.h"
//#include "operator_at_a_time_interface.h"
//#include <unordered_map>
//#include <vector>
//
//#include "expression/attribute.h"
//
// namespace beedb::execution {
// class Aggregator
// {
// public:
// void sum(const std::vector<table::Tuple>& source_tuples, const std::size_t source_index, table::Tuple&
// target_tuple, const std::size_t target_index); void avg(const std::vector<table::Tuple>& source_tuples, const
// std::size_t source_index, table::Tuple& target_tuple, const std::size_t target_index); void min(const
// std::vector<table::Tuple>& source_tuples, const std::size_t source_index, table::Tuple& target_tuple, const
// std::size_t target_index); void max(const std::vector<table::Tuple>& source_tuples, const std::size_t
// source_index, table::Tuple& target_tuple, const std::size_t target_index); void count(const
// std::vector<table::Tuple>& source_tuples, table::Tuple& target_tuple, const std::size_t target_index);
// };
//
// class AggregateOperator : public AbstractOperator, public OperatorAtATimeInterface
// {
// public:
// AggregateOperator(const table::Schema& schema,
// const std::vector<expression::Attribute>& groups,
// const std::vector<expression::Attribute>& columns);
// virtual ~AggregateOperator() = default;
//
// virtual void initialize();
// virtual std::vector<table::Tuple> execute();
// private:
// bool _aggregated = false;
// const std::vector<expression::Attribute>& _groups;
// const std::vector<expression::Attribute>& _columns;
// std::unordered_map<std::uint32_t, const expression::AttributeOrigin> _schema_index_aggregation_map;
// std::unordered_map<std::uint32_t ,std::uint32_t> _schema_index_map;
// std::vector<std::uint32_t> _aggregation_indices;
// std::vector<std::uint32_t> _group_indices;
//
// table::Type aggregation_column_type(const expression::AttributeOrigin aggregation, const table::Type&
// column_type); std::size_t hash(const std::vector<std::uint32_t>& group_indices, const table::Tuple& tuple);
// };
//}

View File

@ -0,0 +1,66 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "operator_interface.h"
#include <memory>
#include <table/schema.h>
#include <table/tuple.h>
namespace beedb::execution
{
/**
* Abstract operator that has to children (left and right)
* for operators JOIN-like operators.
*/
class BinaryOperator : public OperatorInterface
{
public:
BinaryOperator() = default;
virtual ~BinaryOperator() = default;
void left_child(std::unique_ptr<OperatorInterface> child)
{
_left_child = std::move(child);
}
void right_child(std::unique_ptr<OperatorInterface> child)
{
_right_child = std::move(child);
}
const std::unique_ptr<OperatorInterface> &left_child() const
{
return _left_child;
}
const std::unique_ptr<OperatorInterface> &right_child() const
{
return _right_child;
}
protected:
table::Tuple combine(const table::Schema &new_schema, const table::Tuple &left, const table::Tuple &right) const;
private:
std::unique_ptr<OperatorInterface> _left_child;
std::unique_ptr<OperatorInterface> _right_child;
};
} // namespace beedb::execution

View File

@ -0,0 +1,72 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "binary_operator.h"
#include <database.h>
#include <index/index_interface.h>
#include <memory>
#include <string>
#include <table/schema.h>
namespace beedb::execution
{
/**
* Fills an existing index with values.
* May have two children: One operator creating the index (left)
* which is called once and one operator (right) which provides the
* data for the index.
*/
class BuildIndexOperator final : public BinaryOperator
{
public:
BuildIndexOperator(Database &database, const std::string &table_name,
const table::Schema::ColumnIndexType column_index, const std::string &index_name);
virtual ~BuildIndexOperator() = default;
virtual void open();
virtual util::optional<table::Tuple> next();
virtual void close();
virtual const table::Schema &schema() const
{
return _schema;
}
void create_index_operator(std::unique_ptr<OperatorInterface> op)
{
this->left_child(std::move(op));
}
void data_operator(std::unique_ptr<OperatorInterface> op)
{
this->right_child(std::move(op));
}
private:
const table::Schema _schema;
Database &_database;
const std::string _table_name;
const std::uint32_t _column_index;
const std::string _index_name;
};
} // namespace beedb::execution

View File

@ -0,0 +1,72 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "operator_interface.h"
#include <database.h>
#include <disk/buffer_manager.h>
#include <disk/page.h>
#include <index/type.h>
#include <string>
#include <table/table.h>
#include <table/tuple.h>
#include <table/type.h>
#include <tuple>
#include <vector>
namespace beedb::execution
{
/**
* Operator that creates and persists a new index for a given
* column with given index attributes (type, unique or non-unique).
*/
class CreateIndexOperator final : public OperatorInterface
{
public:
CreateIndexOperator(Database &database, const std::string &table_name, const expression::Attribute &attribute,
const std::string &index_name, const bool is_unique, const index::Type type);
virtual ~CreateIndexOperator() = default;
virtual void open()
{
}
virtual util::optional<table::Tuple> next();
virtual void close()
{
}
virtual const table::Schema &schema() const
{
return _schema;
}
private:
const table::Schema _schema;
Database &_database;
const std::string _table_name;
const expression::Attribute _attribute;
const std::string _index_name;
const bool _is_unique;
const index::Type _index_type;
};
} // namespace beedb::execution

View File

@ -0,0 +1,62 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "operator_interface.h"
#include <database.h>
#include <disk/buffer_manager.h>
#include <disk/page.h>
#include <string>
#include <table/table.h>
#include <table/tuple.h>
#include <table/type.h>
#include <tuple>
#include <vector>
namespace beedb::execution
{
/**
* Creates and persists a new table.
*/
class CreateTableOperator final : public OperatorInterface
{
public:
CreateTableOperator(Database &database, const table::Schema schema_to_create);
virtual ~CreateTableOperator() = default;
virtual void open(){};
virtual util::optional<table::Tuple> next();
virtual void close(){};
virtual const table::Schema &schema() const
{
return _schema;
};
private:
Database &_database;
const table::Schema _schema;
const table::Schema _schema_to_create;
};
} // namespace beedb::execution

View File

@ -0,0 +1,58 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "binary_operator.h"
#include <string>
#include <table/memory_table.h>
#include <table/schema.h>
#include <table/tuple.h>
#include <table/value.h>
#include <utility>
#include <vector>
namespace beedb::execution
{
/**
* Generates a cross product of two sources.
*/
class CrossProductOperator final : public BinaryOperator
{
public:
CrossProductOperator(const table::Schema &&schema);
virtual ~CrossProductOperator() = default;
virtual void open();
virtual util::optional<table::Tuple> next();
virtual void close();
virtual const table::Schema &schema() const
{
return _schema;
}
private:
const table::Schema _schema;
util::optional<table::Tuple> _next_left_tuple;
};
} // namespace beedb::execution

View File

@ -0,0 +1,108 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "binary_operator.h"
#include "tuple_buffer.h"
#include <memory>
#include <string>
#include <table/memory_table.h>
#include <table/schema.h>
#include <table/tuple.h>
#include <unordered_map>
#include <utility>
#include <vector>
namespace beedb::execution
{
/**
* Hash table for hash join.
*/
class HashTable
{
public:
HashTable(const std::uint32_t key_index) : _key_index(key_index)
{
}
~HashTable() = default;
bool contains(const table::Value &key)
{
return this->_map.find(key) != _map.end();
}
void put(const table::Tuple &tuple)
{
table::Tuple in_memory_tuple(tuple);
this->_map[tuple.get(_key_index)].push_back(std::move(in_memory_tuple));
}
const std::vector<table::Tuple> &get(const table::Value &key)
{
return _map[key];
}
private:
const std::uint32_t _key_index;
std::unordered_map<table::Value, std::vector<table::Tuple>> _map;
};
/**
* Operator that joins two sources using a hash table over
* the left source.
*/
class HashJoinOperator final : public BinaryOperator
{
public:
HashJoinOperator(const table::Schema schema, const std::uint32_t left_index, const std::uint32_t right_index);
~HashJoinOperator() = default;
virtual void open();
virtual util::optional<table::Tuple> next();
virtual void close();
virtual const table::Schema &schema() const
{
return _schema;
}
private:
const table::Schema _schema;
const std::uint32_t _left_index;
const std::uint32_t _right_index;
HashTable _hash_table;
bool _is_built = false;
TupleBuffer _tuple_buffer;
/**
* Builds the hash table.
*/
void build_hash_table();
/**
* Probes the hash table.
*/
util::optional<table::Tuple> probe_hash_table();
};
} // namespace beedb::execution

View File

@ -0,0 +1,119 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "operator_interface.h"
#include "tuple_buffer.h"
#include <disk/buffer_manager.h>
#include <disk/page.h>
#include <index/index_interface.h>
#include <memory>
#include <queue>
#include <set>
#include <table/table.h>
#include <table/table_disk_manager.h>
#include <table/tuple.h>
#include <vector>
namespace beedb::execution
{
/**
* Key (range) that have to be looked up in the.
* May be a range or a single key.
*/
class KeyRange
{
public:
KeyRange(const std::int64_t single_key) : _from(single_key), _to(std::numeric_limits<std::int64_t>::max())
{
}
KeyRange(const std::int64_t from, const std::int64_t to) : _from(from), _to(to)
{
}
~KeyRange() = default;
bool is_single_key() const
{
return _to == std::numeric_limits<std::int64_t>::max();
}
std::int64_t single_key() const
{
return _from;
}
std::int64_t from() const
{
return _from;
}
std::int64_t to() const
{
return _to;
}
bool operator<(const KeyRange &other) const
{
return _from < other._from;
}
private:
const std::int64_t _from;
const std::int64_t _to;
};
/**
* Takes an index and keys to be looked up in the index
* and scans only over pages found in the index instead
* of scanning all pages from the table.
*/
class IndexScanOperator final : public OperatorInterface
{
public:
IndexScanOperator(const std::uint32_t scan_page_limit, const table::Schema &schema,
disk::BufferManager &buffer_manager, table::TableDiskManager &table_disk_manager,
std::set<KeyRange> &key_ranges, std::shared_ptr<index::IndexInterface> index);
virtual ~IndexScanOperator() = default;
virtual void open();
virtual util::optional<table::Tuple> next();
virtual void close();
virtual const table::Schema &schema() const
{
return _schema;
}
private:
const std::uint32_t _scan_page_limit;
const table::Schema _schema;
disk::BufferManager &_buffer_manager;
table::TableDiskManager &_table_disk_manager;
std::set<KeyRange> _key_ranges;
std::shared_ptr<index::IndexInterface> _index;
std::queue<disk::Page::page_id> _pages_to_scan;
std::vector<disk::Page::page_id> _pinned_pages;
TupleBuffer _buffer;
};
} // namespace beedb::execution

View File

@ -0,0 +1,63 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "unary_operator.h"
#include <disk/buffer_manager.h>
#include <set>
#include <statistic/system_statistics.h>
#include <table/table.h>
#include <table/table_disk_manager.h>
#include <table/tuple.h>
namespace beedb::execution
{
/**
* Inserts all tuples provided by the children operator.
* The child may be a tuple buffer or a subquery.
*/
class InsertOperator final : public UnaryOperator
{
public:
InsertOperator(disk::BufferManager &buffer_manager, table::TableDiskManager &table_disk_manager,
statistic::SystemStatistics &statistics, table::Table &table);
virtual ~InsertOperator() = default;
virtual void open();
virtual util::optional<table::Tuple> next();
virtual void close();
virtual const table::Schema &schema() const
{
return _schema;
}
private:
const table::Schema _schema;
disk::BufferManager &_buffer_manager;
table::TableDiskManager &_table_disk_manager;
statistic::SystemStatistics &_statistics;
table::Table &_table;
disk::Page::page_id _last_pinned_page = disk::Page::INVALID_PAGE_ID;
};
} // namespace beedb::execution

View File

@ -0,0 +1,59 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "unary_operator.h"
#include <cstdint>
#include <table/schema.h>
#include <table/tuple.h>
#include <vector>
namespace beedb::execution
{
/**
* Limits the output result.
*/
class LimitOperator final : public UnaryOperator
{
public:
LimitOperator(const table::Schema &schema, const std::uint64_t limit, const std::uint64_t offset);
virtual ~LimitOperator() = default;
virtual void open();
virtual util::optional<table::Tuple> next();
virtual void close();
virtual const table::Schema &schema() const
{
return _schema;
};
private:
const table::Schema &_schema;
const std::uint64_t _limit;
const std::uint64_t _offset;
bool _has_skipped = false;
std::uint64_t _count = 0;
};
} // namespace beedb::execution

View File

@ -0,0 +1,66 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "binary_operator.h"
#include "predicate_matcher.h"
#include <string>
#include <table/memory_table.h>
#include <table/schema.h>
#include <table/tuple.h>
#include <table/value.h>
#include <utility>
#include <vector>
namespace beedb::execution
{
/**
* Joins two sources by outer-looping over the left
* and inner looping over the right children tuples.
*/
class NestedLoopsJoinOperator final : public BinaryOperator
{
public:
NestedLoopsJoinOperator(const table::Schema &&schema, std::unique_ptr<PredicateMatcherInterface> predicate_matcher);
virtual ~NestedLoopsJoinOperator() = default;
virtual void open();
virtual util::optional<table::Tuple> next();
virtual void close();
virtual const table::Schema &schema() const
{
return _schema;
}
private:
const table::Schema _schema;
std::unique_ptr<PredicateMatcherInterface> _predicate_matcher;
util::optional<table::Tuple> _next_left_tuple;
bool matches(const table::Tuple &left, const table::Tuple &right)
{
return this->_predicate_matcher->matches(left, right);
}
};
} // namespace beedb::execution

View File

@ -0,0 +1,46 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <table/schema.h>
#include <table/tuple.h>
#include <util/optional.h>
namespace beedb::execution
{
/**
* Interface for all physical execution operators.
* The interface is volcano-style (using open, next, and close).
*/
class OperatorInterface
{
public:
OperatorInterface() = default;
virtual ~OperatorInterface() = default;
virtual void open() = 0;
virtual util::optional<table::Tuple> next() = 0;
virtual void close() = 0;
virtual const table::Schema &schema() const = 0;
};
} // namespace beedb::execution

View File

@ -0,0 +1,110 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "unary_operator.h"
#include <cstdint>
#include <memory>
#include <table/memory_table.h>
#include <table/schema.h>
#include <utility>
#include <vector>
namespace beedb::execution
{
/**
* Comparator for comparing two tuples during
* sort.
*/
class TupleComparator
{
public:
TupleComparator(const std::vector<std::pair<std::uint32_t, bool>> &indices) : _indices(indices)
{
}
~TupleComparator() = default;
bool operator()(const table::Tuple &left, const table::Tuple &right) const
{
for (auto &[index, is_ascending] : _indices)
{
const auto value_left = left.get(index);
const auto value_right = right.get(index);
if (is_ascending)
{
if (value_left < value_right)
{
return true;
}
else if (value_left > value_right)
{
return false;
}
}
else
{
if (value_right < value_left)
{
return true;
}
else if (value_right > value_left)
{
return false;
}
}
}
return false;
}
private:
const std::vector<std::pair<std::uint32_t, bool>> &_indices;
};
/**
* Sorts the result provided by a child using quicksort.
*/
class OrderOperator final : public UnaryOperator
{
public:
OrderOperator(const table::Schema &schema, std::vector<std::pair<std::uint32_t, bool>> &&order_columns);
virtual ~OrderOperator() = default;
virtual void open();
virtual util::optional<table::Tuple> next();
virtual void close();
virtual const table::Schema &schema() const
{
return _schema;
}
private:
const table::Schema &_schema;
const std::vector<std::pair<std::uint32_t, bool>> _order_columns;
std::unique_ptr<table::MemoryTable> _result_table;
std::size_t _stack_index = 0u;
};
} // namespace beedb::execution

View File

@ -0,0 +1,268 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <memory>
#include <table/schema.h>
#include <table/tuple.h>
namespace beedb::execution
{
/**
* Interface for predicate matcher. The predicate matcher
* takes one or two tuples and compares them with a constant
* or a value from another tuple.
*/
class PredicateMatcherInterface
{
public:
enum Comparison
{
EQ,
LE,
LT,
GE,
GT,
NEQ
};
virtual ~PredicateMatcherInterface() = default;
virtual bool matches(const table::Tuple &tuple) = 0;
virtual bool matches(const table::Tuple &left, const table::Tuple &right) = 0;
};
/**
* The given tuple will always match.
*/
class AlwaysTrueMatcher final : public PredicateMatcherInterface
{
public:
AlwaysTrueMatcher() = default;
virtual ~AlwaysTrueMatcher() = default;
virtual bool matches(const table::Tuple &)
{
return true;
}
virtual bool matches(const table::Tuple &, const table::Tuple &)
{
return true;
}
};
/**
* Takes two predicate matchers p1 and p2 and connects them using AND.
* Tuple matches when p1 AND p2 matches.
*/
class AndMatcher final : public PredicateMatcherInterface
{
public:
AndMatcher(std::unique_ptr<PredicateMatcherInterface> left, std::unique_ptr<PredicateMatcherInterface> right)
: _left(std::move(left)), _right(std::move(right))
{
}
virtual ~AndMatcher() = default;
virtual bool matches(const table::Tuple &tuple)
{
return _left->matches(tuple) && _right->matches(tuple);
}
virtual bool matches(const table::Tuple &left, const table::Tuple &right)
{
return _left->matches(left, right) && _right->matches(left, right);
}
private:
std::unique_ptr<PredicateMatcherInterface> _left;
std::unique_ptr<PredicateMatcherInterface> _right;
};
/**
* Takes two predicate matchers p1 and p2 and connects them using OR.
* Tuple matches when p1 OR p2 matches.
*/
class OrMatcher final : public PredicateMatcherInterface
{
public:
OrMatcher(std::unique_ptr<PredicateMatcherInterface> left, std::unique_ptr<PredicateMatcherInterface> right)
: _left(std::move(left)), _right(std::move(right))
{
}
virtual ~OrMatcher() = default;
virtual bool matches(const table::Tuple &tuple)
{
return _left->matches(tuple) || _right->matches(tuple);
}
virtual bool matches(const table::Tuple &left, const table::Tuple &right)
{
return _left->matches(left, right) || _right->matches(left, right);
}
private:
std::unique_ptr<PredicateMatcherInterface> _left;
std::unique_ptr<PredicateMatcherInterface> _right;
};
/**
* Compares a specific column in a tuple with a constant.
*/
template <PredicateMatcherInterface::Comparison C> class AttributeValueMatcher final : public PredicateMatcherInterface
{
public:
AttributeValueMatcher(const table::Schema::ColumnIndexType schema_index, const table::Value value)
: _schema_index(schema_index), _value(value)
{
}
~AttributeValueMatcher() = default;
virtual bool matches(const table::Tuple &tuple)
{
if constexpr (C == EQ)
{
return tuple.get(_schema_index) == _value;
}
else if constexpr (C == LE)
{
return tuple.get(_schema_index) <= _value;
}
else if constexpr (C == LT)
{
return tuple.get(_schema_index) < _value;
}
else if constexpr (C == GE)
{
return tuple.get(_schema_index) >= _value;
}
else if constexpr (C == GT)
{
return tuple.get(_schema_index) > _value;
}
else
{
return tuple.get(_schema_index) != _value;
}
}
virtual bool matches(const table::Tuple &, const table::Tuple &)
{
return false;
}
protected:
const table::Schema::ColumnIndexType _schema_index;
const table::Value _value;
};
/**
* Compares two columns in a tuple or one column of two tuples.
*/
template <PredicateMatcherInterface::Comparison C> class AttributeMatcher final : public PredicateMatcherInterface
{
public:
AttributeMatcher(const table::Schema::ColumnIndexType schema_index_left,
const table::Schema::ColumnIndexType schema_index_right)
: _schema_index_left(schema_index_left), _schema_index_right(schema_index_right)
{
}
~AttributeMatcher() = default;
virtual bool matches(const table::Tuple &tuple)
{
if constexpr (C == EQ)
{
return tuple.get(_schema_index_left) == tuple.get(_schema_index_right);
}
else if constexpr (C == LE)
{
return tuple.get(_schema_index_left) <= tuple.get(_schema_index_right);
}
else if constexpr (C == LT)
{
return tuple.get(_schema_index_left) < tuple.get(_schema_index_right);
}
else if constexpr (C == GE)
{
return tuple.get(_schema_index_left) >= tuple.get(_schema_index_right);
}
else if constexpr (C == GT)
{
return tuple.get(_schema_index_left) > tuple.get(_schema_index_right);
}
else
{
return tuple.get(_schema_index_left) != tuple.get(_schema_index_right);
}
}
virtual bool matches(const table::Tuple &left, const table::Tuple &right)
{
if constexpr (C == EQ)
{
return left.get(_schema_index_left) == right.get(_schema_index_right);
}
else if constexpr (C == LE)
{
return left.get(_schema_index_left) <= right.get(_schema_index_right);
}
else if constexpr (C == LT)
{
return left.get(_schema_index_left) < right.get(_schema_index_right);
}
else if constexpr (C == GE)
{
return left.get(_schema_index_left) >= right.get(_schema_index_right);
}
else if constexpr (C == GT)
{
return left.get(_schema_index_left) > right.get(_schema_index_right);
}
else
{
return left.get(_schema_index_left) != right.get(_schema_index_right);
}
}
table::Schema::ColumnIndexType left_index() const
{
return _schema_index_left;
}
table::Schema::ColumnIndexType right_index() const
{
return _schema_index_right;
}
protected:
const table::Schema::ColumnIndexType _schema_index_left;
const table::Schema::ColumnIndexType _schema_index_right;
};
} // namespace beedb::execution

View File

@ -0,0 +1,56 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "unary_operator.h"
#include <cstdint>
#include <string>
#include <table/schema.h>
#include <utility>
#include <vector>
namespace beedb::execution
{
/**
* Applies a new schema to all tuples provided by the children.
* May hide or re-order columns.
*/
class ProjectionOperator final : public UnaryOperator
{
public:
ProjectionOperator(const table::Schema schema);
virtual ~ProjectionOperator() = default;
virtual void open();
virtual util::optional<table::Tuple> next();
virtual void close();
virtual const table::Schema &schema() const
{
return _schema;
}
private:
const table::Schema _schema;
};
} // namespace beedb::execution

View File

@ -0,0 +1,67 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "predicate_matcher.h"
#include "unary_operator.h"
#include <cstdint>
#include <memory>
#include <string>
#include <table/column.h>
#include <table/schema.h>
#include <table/value.h>
namespace beedb::execution
{
/**
* Selects tuples matching a given predicate.
* Some tuples may be filtered.
*/
class SelectionOperator final : public UnaryOperator
{
public:
SelectionOperator(const table::Schema &schema, std::unique_ptr<PredicateMatcherInterface> predicate_matcher);
virtual ~SelectionOperator() = default;
virtual void open();
virtual util::optional<table::Tuple> next();
virtual void close();
virtual const table::Schema &schema() const
{
return _schema;
}
private:
const table::Schema &_schema;
std::unique_ptr<PredicateMatcherInterface> _predicate_matcher;
bool matches(const table::Tuple &tuple)
{
return this->_predicate_matcher->matches(tuple);
}
};
} // namespace beedb::execution

View File

@ -0,0 +1,68 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "tuple_buffer.h"
#include "unary_operator.h"
#include <disk/buffer_manager.h>
#include <disk/page.h>
#include <table/table.h>
#include <table/table_disk_manager.h>
#include <table/tuple.h>
#include <vector>
namespace beedb::execution
{
/**
* Scans all pages of a given table and returns all tuples.
*/
class SequentialScanOperator final : public UnaryOperator
{
public:
SequentialScanOperator(const std::uint32_t scan_page_limit, const table::Schema &schema,
disk::BufferManager &buffer_manager, table::TableDiskManager &table_disk_manager,
const table::Table &table);
virtual ~SequentialScanOperator() = default;
virtual void open();
virtual util::optional<table::Tuple> next();
virtual void close();
virtual const table::Schema &schema() const
{
return _schema;
}
private:
const std::uint32_t _scan_page_limit;
const table::Schema _schema;
disk::BufferManager &_buffer_manager;
table::TableDiskManager &_table_disk_manager;
const table::Table &_table;
disk::Page::page_id _next_page_id_to_scan;
std::vector<disk::Page::page_id> _pinned_pages;
TupleBuffer _buffer;
};
} // namespace beedb::execution

View File

@ -0,0 +1,65 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <table/tuple.h>
#include <vector>
namespace beedb::execution
{
/**
* Buffers tuples; needed by blocking operators.
*/
class TupleBuffer
{
public:
TupleBuffer() = default;
~TupleBuffer() = default;
void add(table::Tuple &tuple)
{
_buffer.push_back(std::move(tuple));
}
void add(std::vector<table::Tuple> &tuples)
{
std::move(tuples.begin(), tuples.end(), std::back_inserter(_buffer));
}
bool empty() const
{
return _buffer.empty() || _head > _buffer.size() - 1;
}
table::Tuple &&pop()
{
return std::move(_buffer[_head++]);
}
void clear()
{
_buffer.clear();
_head = 0u;
}
private:
std::vector<table::Tuple> _buffer;
std::size_t _head = 0u;
};
} // namespace beedb::execution

View File

@ -0,0 +1,68 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "operator_interface.h"
#include "tuple_buffer.h"
#include <table/schema.h>
#include <table/tuple.h>
#include <vector>
namespace beedb::execution
{
/**
* Buffers tuples and pops the on next().
*/
class TupleBufferOperator final : public OperatorInterface
{
public:
TupleBufferOperator(const table::Schema schema);
~TupleBufferOperator() = default;
virtual void open()
{
}
virtual util::optional<table::Tuple> next();
virtual void close()
{
}
virtual const table::Schema &schema() const
{
return _schema;
}
void add(table::Tuple &tuple)
{
_tuple_buffer.add(tuple);
}
void add(std::vector<table::Tuple> &tuples)
{
_tuple_buffer.add(tuples);
}
private:
const table::Schema _schema;
TupleBuffer _tuple_buffer;
};
} // namespace beedb::execution

View File

@ -0,0 +1,50 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "operator_interface.h"
#include <memory>
namespace beedb::execution
{
/**
* Interface for operators providing a single child.
*/
class UnaryOperator : public OperatorInterface
{
public:
UnaryOperator() = default;
virtual ~UnaryOperator() = default;
void child(std::unique_ptr<OperatorInterface> child)
{
_child = std::move(child);
}
const std::unique_ptr<OperatorInterface> &child() const
{
return _child;
}
private:
std::unique_ptr<OperatorInterface> _child;
};
} // namespace beedb::execution

View File

@ -0,0 +1,57 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "unary_operator.h"
#include <cstdint>
#include <table/table_disk_manager.h>
#include <table/value.h>
#include <utility>
#include <vector>
namespace beedb::execution
{
class UpdateOperator : public UnaryOperator
{
public:
UpdateOperator(table::TableDiskManager &table_disk_manager,
std::vector<std::pair<table::Schema::ColumnIndexType, table::Value>> &values)
: _table_disk_manager(table_disk_manager), _new_column_values(std::move(values))
{
}
virtual ~UpdateOperator() = default;
virtual void open();
virtual util::optional<table::Tuple> next();
virtual void close();
virtual const table::Schema &schema() const
{
return _schema;
}
private:
table::Schema _schema;
table::TableDiskManager _table_disk_manager;
std::vector<std::pair<table::Schema::ColumnIndexType, table::Value>> _new_column_values;
};
} // namespace beedb::execution

View File

@ -0,0 +1,212 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <optional>
#include <ostream>
#include <set>
#include <unordered_map>
#include <variant>
#include <vector>
namespace beedb::expression
{
using AttributeName = std::string;
using TableName = std::optional<std::string>;
using Alias = std::optional<std::string>;
using InAscendingOrder = std::optional<bool>;
enum class AttributeOrigin : int
{
PHYSICAL = 0, // the "default"; a physical column
MIXED = 1, // used for Asterisk
AGG_SUM,
AGG_COUNT,
AGG_AVG,
AGG_MIN,
AGG_MAX, // aggregations
ARI_ADD,
ARI_MUL,
ARI_DIV,
ARI_SUB // arithmetic
};
static std::string to_string(AttributeOrigin o)
{
switch (o)
{
case AttributeOrigin::AGG_AVG:
return "AVG";
case AttributeOrigin::AGG_SUM:
return "SUM";
case AttributeOrigin::AGG_COUNT:
return "COUNT";
case AttributeOrigin::AGG_MIN:
return "MIN";
case AttributeOrigin::AGG_MAX:
return "MAX";
case AttributeOrigin::PHYSICAL:
return "PHYSICAL";
default:
return "UNSUPPORTED_FUNCTION";
}
}
// the actual type, that holds attribute information:
// <attribute name,
// table name (optional),
// alias (optional),
// origin (optional),
// order (optional)>
struct Attribute
{
friend std::ostream &operator<<(std::ostream &stream, const Attribute &attribute);
/// MEMBERS:
const AttributeName name;
const TableName table = std::nullopt;
// Note: An alias has no meaning for optimization or consistency
const Alias alias = {};
// Where do values from this attribute come from, a table or an operator?
const AttributeOrigin origin = AttributeOrigin::PHYSICAL;
// Is this attribute (supposed to be) ordered in ascending order?
// false => desc. order, std::nullopt => no specified order
const InAscendingOrder order = std::nullopt;
// string representation of an attribute. alias is prefered, if available.
// combined_name is used for comparison (see operator implementations).
const std::string combined_name = {alias.value_or(
(static_cast<int>(origin) > 1) ? to_string(origin) + "(" + (table ? table.value() + "." : "") + name + ")"
: (table ? table.value() + "." : "") + name)};
/// FUNCTIONS:
operator std::string() const
{
return combined_name;
}
// convenience constructor:
static Attribute create(const Attribute &other, const TableName table_)
{
return Attribute{other.name, table_, other.alias, other.origin, other.order};
}
// operators to utilize stl-classes templated with Attribute
bool operator<(const Attribute &rhs) const
{
// simply compare compound name
return combined_name < rhs.combined_name;
}
bool operator==(const Attribute &rhs) const
{
// simply compare compound name. Note that an alias/tablename is
// useful for disambiguation (e.g. in self-joins)
return (name == rhs.name) && (table == rhs.table) && (origin == rhs.origin);
}
bool operator>(const Attribute &rhs) const
{
// simply compare compound name
return combined_name >= rhs.combined_name;
}
bool operator<=(const Attribute &rhs) const
{
// simply compare compound name
return combined_name < rhs.combined_name;
}
bool operator>=(const Attribute &rhs) const
{
// simply compare compound name
return combined_name >= rhs.combined_name;
}
bool operator!=(const Attribute &rhs) const
{
return combined_name != rhs.combined_name;
}
bool isAsterisk() const
{
// gives true for "*" and "T.*"
return name == "*" && !alias && origin == AttributeOrigin::MIXED && !order;
}
};
/**
* @brief The Asterisk struct is a special instance of Attribute, used for user convenience.
* It will be resolved to a set of Attributes at logical plan creation time.
* E.g. "SELECT * FROM ..." or "SELECT T.* FROM T, ..."
*/
struct Asterisk : Attribute
{
Asterisk(const TableName &table_ = std::nullopt)
: Attribute{"*", table_, std::nullopt, AttributeOrigin::MIXED, std::nullopt}
{
}
};
/**
* Attributes is a set of fully quallified attributes.
*
* "Fully quallified" implies that each attribute also holds its source.
* This can either be a table-name or a result of a computation
* (i.e. aggregation). Table-origin is encoded via string, aggregation (or
* not via type/template).
*
* Newly produced columns hold a generated table name for intermediate
* tables and a generated name (such as "SUM(T.A)").
*
* Attributes's set-property enforces unique attributes in the collection.
* Note that an attribute's alias is used for disambiguation.
*/
using Attributes = std::vector<Attribute>;
static inline Attributes recreateAttributes(const Attributes &other_attr, const std::string &table_name)
{
Attributes attributes;
for (const auto &attr : other_attr)
{
attributes.push_back(Attribute::create(attr, table_name));
}
return attributes;
}
static inline std::string to_string(const Attributes &attributes)
{
std::string ret = "";
for (const auto &attr : attributes)
{
ret += " ";
ret += attr;
}
return ret;
}
} // namespace beedb::expression

View File

@ -0,0 +1,684 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "expression/attribute.h"
#include "expression/predicate.h"
#include <cassert>
#include <index/type.h>
#include <sstream>
#include <table/type.h>
namespace beedb::expression
{
using namespace std::string_literals;
/**
* A RequiredSchema is a set of required attributes. Requirements of scan operators are checked differently.
*/
using RequiredSchema = Attributes;
/**
* This is the schema produced by an operator. It is represented as an edge "weight"/data in the graph.
*/
using OutgoingSchema = Attributes;
/**
* This is the schema/attributes that are produced by an operator, e.g. by aggregations.
*/
using AttributeAdditions = Attributes;
/**
* @brief The Operator struct represents operators as nodes in the graph.
*
* Depending on the type, operators can provide additional data, aside from
* "required schema" and "working schema":
*
* Logically relevant operators:
* CROSSPRODUCT: /
* JOIN: predicate
* SELECTION: predicate
* PROJECTION: /
* AGGREGATION: /
* GROUPBY: /
* QUERY: logical plan
* ARITHMETIC: an arithmetic constant (optional)
*
*
*/
struct Operator
{
Operator(const RequiredSchema requirements_, const AttributeAdditions additional_attributes_,
const bool forwards_schema_)
: requirements(requirements_), additional_attributes(additional_attributes_), forwards_schema(forwards_schema_)
{
}
virtual ~Operator() = default;
RequiredSchema requirements; // attributes an operator requires
AttributeAdditions additional_attributes; // the attributes an operator works on
// This attribute indicates that an operator type forwards incoming
// attributes or not. This is subclass-dependet information.
// It is used when infering outgoing schemas of an operator. This
// information can not be derived by the operator itself, because it
// depends on it's position in the plan.
const bool forwards_schema;
/**
* @brief inferPredicateRequirements is a utility function, that
* extracts attributes from a predicate tree.
*
* Uses extractAttributes() as a helper function.
*
* Used in JOIN/SELECTION subclasses.
*
* @param pred the predicate, that contains attributes
* @return the extracted attributes
*/
static RequiredSchema inferPredicateRequirements(const Predicate &pred)
{
return PredicateAnalyzer::attributes(pred);
}
/**
* @brief inferAggregationRequirements is a utility function, that
* extracts required attributes. this is implemented by replacing
* the origin (field within an attribute) with a physical origin.
*
* This can be interpreted as " Attribute 'SUM(A)' requires attribute
* 'A' to be computable."
*
* Used in AGGREGATION/GROUPBY subclasses.
*
* @param agg_attributes the attributes that might contain aggregations
* @return attributes with origin set to physical
*/
static RequiredSchema inferStatementRequirements(const Attributes &agg_attributes)
{
Attributes requirements;
// simply clone attributes without aggregation-origin (and physical origin instead):
for (const auto &attr : agg_attributes)
{
requirements.push_back({attr.name, attr.table, attr.alias, AttributeOrigin::PHYSICAL});
}
return requirements;
}
/**
* @brief operator std::string gives a representation of the operator.
*/
operator std::string() const
{
return to_string();
}
/**
* @brief clone creates an new instance of an operator.
* @return an exact copy of this
*/
virtual std::unique_ptr<Operator> clone() const = 0;
protected:
virtual std::string to_string() const = 0;
};
/**
* @brief The TABLE struct produces (physically existing) attributes of a
* single, specific table.
*/
struct TableOperator : Operator
{
TableOperator(const AttributeAdditions table_attributes, const std::string &table_name)
: Operator{{/*no requirements*/}, table_attributes, false}, _table_name(table_name), _table_alias{std::nullopt}
{
// consistency check: we may only produce attributes from a single
// table
std::set<std::string> tablenames;
for (const auto &attribute : table_attributes)
{
assert(attribute.origin == AttributeOrigin::PHYSICAL);
assert(attribute.table.has_value());
tablenames.insert(attribute.table.value());
}
assert(tablenames.size() == 1); // table name/alias has to be the same for all attributes of this operator
if (table_attributes.back().table.value() != _table_name)
{
_table_alias = table_attributes.back().table.value();
}
}
virtual ~TableOperator() = default;
std::string to_string() const override
{
return "TABLE( " + _table_name + " )";
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<TableOperator>(this->additional_attributes, this->_table_name);
}
const std::string &physical_table_name() const
{
return _table_name;
}
const std::optional<std::string> table_alias() const
{
return _table_alias;
}
private:
const std::string _table_name;
std::optional<std::string> _table_alias;
};
struct IndexScanOperator : Operator
{
IndexScanOperator(const AttributeAdditions table_attributes, const std::string &table_name_, Predicate &&predicate_,
expression::Attribute indexed_attribute_)
: Operator{inferPredicateRequirements(predicate_), table_attributes, false}, table_name(table_name_),
predicate(std::move(predicate_)), indexed_attribute(indexed_attribute_)
{
}
virtual ~IndexScanOperator() = default;
std::string to_string() const override
{
return "INDEX_SCAN( " + table_name + " )";
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<IndexScanOperator>(this->additional_attributes, this->table_name,
expression::clone_predicate(predicate), indexed_attribute);
}
const std::string table_name;
Predicate predicate;
expression::Attribute indexed_attribute;
};
/**
* @brief The CROSSPRODUCT struct is just a union of incoming attributes
* and therefore solely defined by its placement in the graph
*/
struct CrossProductOperator : public Operator
{
CrossProductOperator() : Operator{{}, {}, true}
{
}
virtual ~CrossProductOperator() = default;
std::string to_string() const override
{
return "CROSSPRODUCT"s;
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<CrossProductOperator>();
}
};
/**
* @brief The JOIN struct is defined by it's predicate (in
* addition to its placement)
*/
struct JoinOperator : public Operator
{
enum Type
{
NestedLoopsJoin,
HashJoin
};
JoinOperator(Predicate &&join_predicate, const Type type_)
: Operator{inferPredicateRequirements(join_predicate), {/* No additions*/}, true},
predicate(std::move(join_predicate)), type(type_)
{
}
virtual ~JoinOperator() = default;
Predicate predicate;
const Type type;
std::string to_string() const override
{
std::string pred_str;
std::visit(expression::LogicalConnective::TermStringifier{pred_str}, predicate);
std::string str;
str += (type == NestedLoopsJoin) ? "NESTEDLOOPSJOIN" : "HASHJOIN";
str += "( ";
str += pred_str;
str += " )";
return str;
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<JoinOperator>(expression::clone_predicate(this->predicate), type);
}
};
/**
* @brief The SELECTION struct represents a simple filter operator.
* Requirements are derived from the specified predicate.
*/
struct SelectionOperator : public Operator
{
// we can only select from attributes that we get => requirements:
SelectionOperator(Predicate &&selection_predicate)
: Operator{inferPredicateRequirements(selection_predicate), {/* No additions*/}, true},
predicate(std::move(selection_predicate))
{
}
virtual ~SelectionOperator() = default;
Predicate predicate;
std::string to_string() const override
{
std::string pred_str;
std::visit(expression::LogicalConnective::TermStringifier{pred_str}, predicate);
return "SELECTION( " + pred_str + " )";
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<SelectionOperator>(expression::clone_predicate(this->predicate));
}
};
/**
* @brief The PROJECTION struct reduces the incoming attributes to the
* specified set.
*/
struct ProjectionOperator : public Operator
{
// we can only project what is coming in => requirements:
ProjectionOperator(const RequiredSchema projected_attributes)
: Operator{projected_attributes, {/* No additions */}, false}
{
}
virtual ~ProjectionOperator() = default;
std::string to_string() const override
{
std::string str("PROJECTION( ");
for (const auto &attr : this->additional_attributes)
{
str += static_cast<std::string>(attr) + " ";
}
str += ")";
return str;
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<ProjectionOperator>(this->requirements);
}
};
/**
* @brief The AGGREGATION struct performs an aggregation operation and
* creates a new column.
*
* Also, it forwards all other incoming columns,
* including the one that this operation is based on.
*
* I.e. {"A"} x {"A*4"} -> {"A","A*4"}
*/
struct AggregationOperator : public Operator
{
AggregationOperator(const AttributeAdditions resulting_attributes)
: Operator{inferStatementRequirements(resulting_attributes), resulting_attributes, false}
{
}
virtual ~AggregationOperator() = default;
std::string to_string() const override
{
return "AGGREGATION"s;
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<AggregationOperator>(this->additional_attributes);
}
};
/**
* @brief The GROUPBY struct is similar to aggregation
*
*/
struct GroupByOperator : public AggregationOperator
{
// GROUPBY is an AGGREGATION
GroupByOperator(const AttributeAdditions resulting_attributes) : AggregationOperator{resulting_attributes}
{
}
virtual ~GroupByOperator() = default;
std::string to_string() const override
{
std::string str("GROUPBY( ");
for (const auto &attr : this->additional_attributes)
{
str += attr;
str += " ";
}
str += ")";
return str;
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<GroupByOperator>(this->additional_attributes);
}
};
struct OrderByOperator : public Operator
{
OrderByOperator(const AttributeAdditions sorted_attributes)
: Operator{sorted_attributes, {/* No additions */}, true}
{
for (const auto &attribute : sorted_attributes)
{
assert(attribute.order.has_value()); // we can only make use of attributes that have an order specified
}
}
virtual ~OrderByOperator() = default;
std::string to_string() const override
{
std::string str("ORDERBY( ");
for (const auto &attr : this->additional_attributes)
{
str += static_cast<std::string>(attr) + "(";
str += (attr.order.value() ? "ASC"s : "DESC"s);
str += ") ";
}
str += ")";
return str;
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<OrderByOperator>(this->requirements);
}
};
/**
* @brief The ARITHMETIC struct is a binary arithmetic operation between
* values from columns or constants.
*
* The type of operation itself is encoded in the specified attributes!
*/
struct ArithmeticOperator : public Operator
{
using ArithmeticConstant = std::optional<std::variant<float, long>>;
// An arithmetic operation is defined by the
ArithmeticOperator(const AttributeAdditions resulting_attributes, const ArithmeticConstant constant_ = {})
: Operator{inferStatementRequirements(resulting_attributes), resulting_attributes, true}, constant(constant_)
{
}
virtual ~ArithmeticOperator() = default;
ArithmeticConstant constant;
std::string to_string() const override
{
return "ARITHMETIC"s;
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<ArithmeticOperator>(this->additional_attributes);
}
};
struct LimitOperator : public Operator
{
LimitOperator(const std::uint64_t limit_, const std::uint64_t offset_)
: Operator({}, {}, true), limit(limit_), offset(offset_)
{
}
virtual ~LimitOperator() = default;
const std::uint64_t limit;
const std::uint64_t offset;
std::string to_string() const override
{
return "LIMIT( " + std::to_string(offset) + "," + std::to_string(limit) + " )";
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<LimitOperator>(limit, offset);
}
};
/**
* @brief The QUERY struct embeds a subquery into this plan.
*/
struct QueryOperator : public Operator
{
// QUERY is another plan, nested into the current plan.
QueryOperator(const RequiredSchema input_schema, const AttributeAdditions output_schema
// , const LogicalPlan& nested_plan
)
: Operator{input_schema, output_schema, false}
{
}
virtual ~QueryOperator() = default;
// LogicalPlan nested_plan; // TODO: move operator defintions
std::string to_string() const override
{
return "SUBQUERY"s;
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<QueryOperator>(this->requirements, this->additional_attributes);
}
};
struct CreateTableOperator : public Operator
{
CreateTableOperator(const std::string &table_name_, std::vector<std::string> &&column_names_,
std::vector<table::Type> &&column_types_, std::vector<bool> &&column_is_nullables_)
: Operator({}, {}, false), table_name(table_name_), column_names(column_names_), column_types(column_types_),
column_is_nullables(column_is_nullables_)
{
}
virtual ~CreateTableOperator() = default;
const std::string table_name;
const std::vector<std::string> column_names;
const std::vector<table::Type> column_types;
const std::vector<bool> column_is_nullables;
std::string to_string() const override
{
std::stringstream stream;
stream << "CREATE TABLE " << table_name << " (";
for (auto i = 0u; i < column_names.size(); i++)
{
stream << column_names[i] << " (" << column_types[i].name() << " ";
if (column_is_nullables[i])
{
stream << "NULL";
}
else
{
stream << "NOT NULL";
}
stream << ")";
if (i < column_names.size() - 1)
{
stream << ",";
}
}
stream << " )";
return stream.str();
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<CreateTableOperator>(table_name, std::vector<std::string>(column_names),
std::vector<table::Type>(column_types),
std::vector<bool>(column_is_nullables));
}
};
struct CreateIndexOperator : Operator
{
CreateIndexOperator(Attribute &&indexed_attribute, const std::string &index_name_, const bool is_unique_,
const index::Type index_type)
: Operator({}, {}, false), column(indexed_attribute), index_name(index_name_), is_unique(is_unique_),
type(index_type)
{
}
virtual ~CreateIndexOperator() = default;
const Attribute column;
const std::string index_name;
const bool is_unique;
const index::Type type;
std::string to_string() const override
{
return "CREATE INDEX " + index_name + " ON " + column.combined_name;
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<CreateIndexOperator>(expression::Attribute{column}, index_name, is_unique, type);
}
};
struct InsertOperator : Operator
{
InsertOperator(const std::string &table_name_, const Attributes columns,
const std::vector<std::vector<std::optional<Operand>>> &value_lists_)
: Operator({}, columns, false), table_name(table_name_), values_lists(value_lists_)
{
}
~InsertOperator() = default;
const std::string table_name;
const std::vector<std::vector<std::optional<Operand>>> values_lists;
std::string to_string() const override
{
std::stringstream stream;
stream << "INSERT INTO " << table_name << " (";
for (auto i = 0u; i < this->additional_attributes.size(); i++)
{
if (i > 0u)
{
stream << ",";
}
stream << this->additional_attributes[i].combined_name;
}
stream << ") VALUES ";
for (auto i = 0u; i < values_lists.size(); i++)
{
if (i > 0u)
{
stream << ",";
}
stream << "(";
const auto &tuple = values_lists[i];
for (auto j = 0u; j < tuple.size(); j++)
{
if (j > 0u)
{
stream << ",";
}
if (tuple[j])
{
std::visit([&stream](const auto &value) { stream << value; }, tuple[j].value());
}
else
{
stream << "NULL";
}
}
stream << ")";
}
stream << std::flush;
return stream.str();
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<InsertOperator>(table_name, additional_attributes, values_lists);
}
};
struct UpdateOperator : public Operator
{
UpdateOperator(const std::vector<std::pair<Attribute, Operand>> &updates_)
: Operator({}, {}, false), updates(updates_)
{
}
virtual ~UpdateOperator() = default;
std::vector<std::pair<Attribute, Operand>> updates;
std::string to_string() const override
{
return "UPDATE";
}
std::unique_ptr<Operator> clone() const override
{
return std::make_unique<UpdateOperator>(updates);
}
};
} // namespace beedb::expression

View File

@ -0,0 +1,493 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "expression/attribute.h"
#include <cassert>
#include <exception/logical_exception.h>
#include <memory>
#include <string>
#include <variant>
#include <vector>
namespace beedb::expression
{
/**
* This represents the result of a predicate. We need ternary logic, since all
* predicates, that involve attributes, can not be resolved statically.
* Therefore, only constants can evaluate to either true or false, everything
* else will result in std::nullopt, i.e. no result.
*
* This can be used to statically evaluate literal predicates at plan-creation
* time.
*
* TODO: finish implementation, when this feature is needed.
*/
using TernaryValue = std::optional<bool>;
/**
* Operand of a predicate, type is defined by the parser.
*
* Node: Unequal types always compare to False. I.e. "1.0f == 1l" give False
*/
using Operand = std::variant<Attribute, std::string, std::int64_t, float, bool>;
struct Atom
{
const Operand left;
const Operand right;
Atom(const Operand left_, const Operand right_) : left(left_), right(right_)
{
}
virtual ~Atom() = default;
virtual std::unique_ptr<Atom> clone(const Operand &left, const Operand &right) const = 0;
std::unique_ptr<Atom> clone()
{
return this->clone(left, right);
}
virtual operator TernaryValue() const = 0;
operator std::string() const
{
std::string left_string;
std::visit(OperandStringifier{left_string}, left);
std::string right_string;
std::visit(OperandStringifier{right_string}, right);
return left_string + " " + operatorString() + " " + right_string;
}
protected:
virtual std::string operatorString() const = 0;
bool semantic_check() const
{
if (std::holds_alternative<Attribute>(left) || std::holds_alternative<Attribute>(right))
{
return false;
}
else if (left.index() != right.index())
{
throw exception::LogicalException("No support for operands of different literal types!");
}
return true;
}
struct OperandStringifier
{
// helper struct for visitor pattern.
// implements string conversion of atoms by calling the
// proper conversion operation on the operands
std::string &rep;
// depending on the variant type,
// c++ picks the appropiate call operator
// NOTE: 'overload' might be of use here
// https://www.bfilipek.com/2018/06/variant.html#overload
void operator()(std::int64_t const &val)
{
rep = std::to_string(val); // converts operand to std::string
}
void operator()(float const &val)
{
rep = std::to_string(val); // converts operand to std::string
}
void operator()(bool const &val)
{
rep = std::to_string(std::int32_t(val)); // converts operand to std::string
}
void operator()(std::string const &val)
{
rep = "\'" + val + "\'"; // converts operand to std::string
}
void operator()(Attribute const &val)
{
rep = val; // casts to string
}
};
};
struct EQ : public Atom
{
EQ(const Operand left_, const Operand right_) : Atom{left_, right_}
{
}
std::unique_ptr<Atom> clone(const Operand &left_, const Operand &right_) const override
{
return std::make_unique<EQ>(left_, right_);
}
operator TernaryValue() const override
{
return semantic_check() ? std::optional(left == right) : std::nullopt;
}
std::string operatorString() const override
{
return "=";
}
};
struct NEQ : public Atom
{
NEQ(const Operand left_, const Operand right_) : Atom{left_, right_}
{
}
std::unique_ptr<Atom> clone(const Operand &left_, const Operand &right_) const override
{
return std::make_unique<NEQ>(left_, right_);
}
operator TernaryValue() const override
{
return semantic_check() ? std::optional(left != right) : std::nullopt;
}
std::string operatorString() const override
{
return "!=";
}
};
struct LT : public Atom
{
LT(const Operand left_, const Operand right_) : Atom{left_, right_}
{
}
std::unique_ptr<Atom> clone(const Operand &left_, const Operand &right_) const override
{
return std::make_unique<LT>(left_, right_);
}
operator TernaryValue() const override
{
return semantic_check() ? std::optional(left < right) : std::nullopt;
}
std::string operatorString() const override
{
return "<";
}
};
struct GT : public Atom
{
GT(const Operand left_, const Operand right_) : Atom{left_, right_}
{
}
std::unique_ptr<Atom> clone(const Operand &left_, const Operand &right_) const override
{
return std::make_unique<GT>(left_, right_);
}
operator TernaryValue() const override
{
return semantic_check() ? std::optional(left > right) : std::nullopt;
}
std::string operatorString() const override
{
return ">";
}
};
struct LE : public Atom
{
LE(const Operand left_, const Operand right_) : Atom{left_, right_}
{
}
std::unique_ptr<Atom> clone(const Operand &left_, const Operand &right_) const override
{
return std::make_unique<LE>(left_, right_);
}
operator TernaryValue() const override
{
return semantic_check() ? std::optional(left <= right) : std::nullopt;
}
std::string operatorString() const override
{
return "<=";
}
};
struct GE : public Atom
{
GE(const Operand left_, const Operand right_) : Atom{left_, right_}
{
}
std::unique_ptr<Atom> clone(const Operand &left_, const Operand &right_) const override
{
return std::make_unique<GE>(left_, right_);
}
operator TernaryValue() const override
{
return semantic_check() ? std::optional(left >= right) : std::nullopt;
}
std::string operatorString() const override
{
return ">=";
}
};
/**
* Recursive definition of a predicate. Can either be an atom or a two-term
* combination of other predicates:
*/
struct LogicalConnective;
using Predicate = std::variant<std::unique_ptr<LogicalConnective>, std::unique_ptr<Atom>, bool>;
/**
* @brief The Expression struct defines the logical combination of two
* Predicate objects.
*/
struct LogicalConnective
{
protected:
LogicalConnective(Predicate &&left_, Predicate &&right_) : left(std::move(left_)), right(std::move(right_))
{
}
public:
virtual ~LogicalConnective() = default;
virtual std::unique_ptr<LogicalConnective> clone() const = 0;
Predicate left;
Predicate right;
/**
* @brief operator bool makes evaluation of expressions possible.
*/
operator TernaryValue() const
{
TernaryValue left_result;
std::visit(TermEvaluator{left_result}, left);
TernaryValue right_result;
std::visit(TermEvaluator{right_result}, right);
return apply(left_result, right_result);
}
operator std::string() const
{
std::string left_result;
std::visit(TermStringifier{left_result}, left);
std::string right_result;
std::visit(TermStringifier{right_result}, right);
return "(" + left_result + " " + connector() + " " + right_result + ")";
}
struct TermEvaluator
{
// helper struct for visitor pattern
// implements boolean evaluation of expressions by calling the
// proper conversion operation (to bool-conversion)
TernaryValue &result;
// depending on the variant type,
// c++ picks the appropiate call operator:
void operator()(const std::unique_ptr<Atom> &atom)
{
result = static_cast<TernaryValue>(*atom); // converts atom to bool
}
void operator()(const std::unique_ptr<LogicalConnective> &expression)
{
result = static_cast<TernaryValue>(*expression);
}
void operator()(const bool truth_value)
{
result = truth_value;
}
};
struct TermStringifier
{
// helper struct for visitor pattern
// implements boolean evaluation of expressions by calling the
// proper conversion operation (to bool-conversion)
std::string &rep;
// depending on the variant type,
// c++ picks the appropiate call operator:
void operator()(const std::unique_ptr<Atom> &atom)
{
rep = static_cast<std::string>(*atom); // converts atom to bool
}
void operator()(const std::unique_ptr<LogicalConnective> &expression)
{
rep = static_cast<std::string>(*expression);
}
void operator()(const bool truth_value)
{
rep = truth_value ? "True" : "False";
}
};
protected:
virtual TernaryValue apply(TernaryValue, TernaryValue) const = 0;
virtual std::string connector() const = 0;
};
static inline std::string to_string(const Predicate &predicate)
{
std::string str;
std::visit(LogicalConnective::TermStringifier{str}, predicate);
return str;
}
static inline TernaryValue statically_evaluate(const Predicate &predicate)
{
TernaryValue result;
std::visit(LogicalConnective::TermEvaluator{result}, predicate);
return result;
}
static inline Predicate clone_predicate(const Predicate &predicate)
{
if (std::holds_alternative<std::unique_ptr<LogicalConnective>>(predicate))
{
return std::get<std::unique_ptr<LogicalConnective>>(predicate)->clone();
}
else if (std::holds_alternative<std::unique_ptr<Atom>>(predicate))
{
return std::get<std::unique_ptr<Atom>>(predicate)->clone();
}
else if (std::holds_alternative<bool>(predicate))
{
return std::get<bool>(predicate);
}
assert(false && "Could not clone predicate");
return {};
}
struct AND : public LogicalConnective
{
AND(Predicate &&left_, Predicate &&right_) : LogicalConnective(std::move(left_), std::move(right_))
{
}
std::unique_ptr<LogicalConnective> clone() const override
{
auto left_clone = clone_predicate(left);
auto right_clone = clone_predicate(right);
return std::make_unique<AND>(std::move(left_clone), std::move(right_clone));
}
TernaryValue apply(TernaryValue left_, TernaryValue right_) const override
{
if (left_.has_value())
{
if (!left_.value())
{ // if the lhs expression is False...
// ... the whole statement is always False!
return false;
}
return right_; // .. if true, AND is a neutral/redundant operation
}
else if (right_.has_value())
{
if (!right_.value())
{ // if the rhs expression is False...
// ... the whole statement is always False!
return false;
}
return left_; // .. if true, AND is a neutral/redundant operation
}
else
{
// when both values are std::nullopt, then....
return std::nullopt; // ..this statement is not statically evaluable!
}
}
std::string connector() const override
{
return "&&";
}
};
struct OR : public LogicalConnective
{
OR(Predicate &&left_, Predicate &&right_) : LogicalConnective(std::move(left_), std::move(right_))
{
}
std::unique_ptr<LogicalConnective> clone() const override
{
auto left_clone = clone_predicate(left);
auto right_clone = clone_predicate(right);
return std::make_unique<OR>(std::move(left_clone), std::move(right_clone));
}
TernaryValue apply(TernaryValue left_, TernaryValue right_) const override
{
if (left_.has_value())
{
if (left_.value())
{ // if the lhs expression is True...
// ... the whole statement is always True!
return true;
}
return right_; // .. if False, OR is a neutral/redundant operation
}
else if (right_.has_value())
{
if (right_.value())
{ // if the rhs expression is True...
// ... the whole statement is always true!
return true;
}
return left_; // .. if False, OR is a neutral/redundant operation
}
else
{
// when both values are std::nullopt, then....
return std::nullopt; // ..this statement is not statically evaluable!
}
}
std::string connector() const override
{
return "||";
}
};
class PredicateAnalyzer
{
public:
static expression::Attributes attributes(const Predicate &predicate);
static bool contains_range_predicate(const Predicate &predicate);
static bool contains_not_equals_predicate(const Predicate &predicate);
};
} // namespace beedb::expression

View File

@ -0,0 +1,285 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "b_plus_tree_node.h"
#include "index/non_unique_index_interface.h"
#include "index/return_value.h"
#include <cstdint>
#include <optional>
#include <ostream>
#include <set>
#include <utility>
#include <vector>
namespace beedb::index::bplustree
{
template <typename K, typename V, bool U> class BPlusTree
{
public:
using Node = BPlusTreeNode<K, V, U>;
BPlusTree() : _root(new Node(true))
{
}
~BPlusTree()
{
delete _root;
}
/**
* Inserts the given key-value-pair into the tree.
*
* @param key
* @param value
*/
void put(const K key, V value);
/**
* Finds the value by the given key.
*
* @param key
* @return The found value.
*/
std::optional<typename ReturnValue<V, U>::type> get(const K key) const;
std::optional<std::set<V>> get(const K key_from, const K key_to) const;
inline Node *root() const
{
return _root;
}
inline size_type height() const
{
return _height;
}
private:
Node *_root;
size_type _height = 1;
/**
* Locates a leaf node for a given key.
*
* @param key
* @param node_path
* @return
*/
Node *locate_leaf(const K key, std::vector<Node *> *node_path = nullptr) const;
/**
* Inserts the given key-value-tuple into the give leaf node.
*
* @param leaf_node
* @param key
* @param value
* @return
*/
Node *insert_into_leaf(Node *leaf_node, const K key, const V value);
/**
* Inserts the given key and separator into the given inner node.
*
* @param inner_node
* @param key
* @param separator
* @return
*/
std::pair<Node *, K> insert_into_inner(Node *inner_node, const K key, Node *separator);
/**
* Creates a new root with pointer to the two given new child nodes.
*
* @param left
* @param right
* @param key
*/
void install_new_root_node(Node *left, Node *right, const K key);
/**
* Splits the given inner node and returns the new node and a key,
* that has to be inserted into the parent node.
*
* @param inner_node
* @param key
* @param separator
* @return
*/
std::pair<Node *, K> split_inner_node(Node *inner_node, const K key, Node *separator);
/**
* Splits the given leaf node and returns the new node.
*
* @param leaf_node
* @return
*/
Node *split_leaf_node(Node *leaf_node);
friend std::ostream &operator<<(std::ostream &stream, const BPlusTree<K, V, U> &tree)
{
Node *root = tree.root();
if (root == nullptr)
{
return stream;
}
const auto items = tree.root()->size_include_children();
const auto nodes = tree.root()->count_children();
return stream << "Height = " << tree.height() << "\n"
<< "Key-Value-Pairs = " << items.second << "\n"
<< "Inner-Nodes = " << nodes.first << "\n"
<< "Leaf-Nodes = " << nodes.second << "\n"
<< "Memory = "
<< ((nodes.first + nodes.second) * Config::b_plus_tree_page_size) / 1024 / 1024 << " MB\n";
}
};
template <typename K, typename V, bool U> void BPlusTree<K, V, U>::put(const K key, V value)
{
// Path for traversal. All nodes from root excluding the leaf node will be stored.
std::vector<Node *> path;
path.reserve(6);
// Locate the possible leaf.
Node *leaf = this->locate_leaf(key, &path);
// Insert into leaf
K up_key;
Node *new_node = this->insert_into_leaf(leaf, key, value);
if (new_node != nullptr)
{
up_key = new_node->leaf_key(0u);
}
// Propagate up.
while (new_node != nullptr && path.empty() == false)
{
Node *parent = path.back();
path.pop_back();
auto [n, u] = this->insert_into_inner(parent, up_key, new_node);
new_node = n;
up_key = u;
}
// Create new root
if (new_node != nullptr)
{
this->install_new_root_node(_root, new_node, up_key);
}
}
template <typename K, typename V, bool U>
std::pair<BPlusTreeNode<K, V, U> *, K> BPlusTree<K, V, U>::insert_into_inner(BPlusTree<K, V, U>::Node *inner_node,
const K key,
BPlusTree<K, V, U>::Node *separator)
{
if (inner_node->is_full() == false)
{
const size_type index = inner_node->index(key);
inner_node->insert_separator(index, separator, key);
return {static_cast<Node *>(nullptr), 0};
}
else
{
return this->split_inner_node(inner_node, key, separator);
}
}
template <typename K, typename V, bool U>
void BPlusTree<K, V, U>::install_new_root_node(BPlusTree<K, V, U>::Node *left, BPlusTree<K, V, U>::Node *right,
const K key)
{
Node *new_root = new Node(false);
new_root->separator(0, left);
new_root->insert_separator(0, right, key);
_height++;
_root = new_root;
}
template <typename K, typename V, bool U>
std::pair<BPlusTreeNode<K, V, U> *, K> BPlusTree<K, V, U>::split_inner_node(BPlusTree<K, V, U>::Node *inner_node,
const K key,
BPlusTree<K, V, U>::Node *separator)
{
constexpr size_type left_size = BPlusTreeInnerNode<K, V, U>::max_keys / 2;
constexpr size_type right_size = BPlusTreeInnerNode<K, V, U>::max_keys - left_size;
K key_up;
Node *new_inner_node = new Node(false);
new_inner_node->right(inner_node->right());
inner_node->right(new_inner_node);
if (key < inner_node->inner_key(left_size - 1))
{
inner_node->copy(new_inner_node, left_size, right_size);
new_inner_node->separator(0, inner_node->separator(left_size));
new_inner_node->size(right_size);
key_up = inner_node->inner_key(left_size - 1);
inner_node->size(left_size - 1);
const size_type index = inner_node->index(key);
inner_node->insert_separator(index, separator, key);
}
else if (key < inner_node->inner_key(left_size))
{
inner_node->copy(new_inner_node, left_size, right_size);
new_inner_node->separator(0, separator);
key_up = key;
inner_node->size(left_size);
new_inner_node->size(right_size);
}
else
{
inner_node->copy(new_inner_node, left_size + 1, right_size - 1);
new_inner_node->separator(0, inner_node->separator(left_size + 1));
inner_node->size(left_size);
new_inner_node->size(right_size - 1);
key_up = inner_node->inner_key(left_size);
const size_type index = new_inner_node->index(key);
new_inner_node->insert_separator(index, separator, key);
}
return {new_inner_node, key_up};
}
template <typename K, typename V, bool U>
BPlusTreeNode<K, V, U> *BPlusTree<K, V, U>::split_leaf_node(BPlusTree<K, V, U>::Node *leaf_node)
{
constexpr size_type left_size = BPlusTreeLeafNode<K, V, U>::max_items / 2;
constexpr size_type right_size = BPlusTreeLeafNode<K, V, U>::max_items - left_size;
Node *new_leaf_node = new Node(true);
new_leaf_node->right(leaf_node->right());
leaf_node->right(new_leaf_node);
leaf_node->copy(new_leaf_node, left_size, right_size);
new_leaf_node->size(right_size);
leaf_node->size(left_size);
return new_leaf_node;
}
} // namespace beedb::index::bplustree
#include "b_plus_tree.hpp"

View File

@ -0,0 +1,200 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include "index/return_value.h"
#include <index/b_plus_tree/b_plus_tree_node.h>
#include <iostream>
#include <optional>
#include <utility>
#include <vector>
namespace beedb::index::bplustree
{
template <typename K, typename V, bool U>
BPlusTreeNode<K, V, U> *BPlusTree<K, V, U>::locate_leaf(const K key,
std::vector<BPlusTreeNode<K, V, U> *> *node_path) const
{
/**
* Assignment (2): Implement a B+-Tree
*
* The B+-Tree is used for indexing files. Using the index
* for bigger data sets will reduce the amount of scanned disk pages
* in case the query wants to filter the data.
*
* This method is used to traverse the tree and locate a leaf that may
* contain the wanted key. During the traversal for inserts, all visited nodes
* are stored in the node_path container. For lookups, the container is null.
*
* Hints for implementation:
* - "this->_root" stores the root node of the tree, where every
* lookup for a leaf is started.
* - Every inner node (also the root) has a "child(k)" method, which returns
* the next node on the way for the leaf, that may contain the key "k".
* - To check a node whether it is a leaf or inner node, use the "is_leaf()"
* method on a node, which returns true if the node is a leaf.
* - If "node_path" is not a "nullptr", push all nodes during traversal
* to that vector (also the root).
*
*
* Procedure:
* - Start the traversal at the root node.
* - Get the next node using "current_node->child(key)" while "current_node"
* is not a leaf.
* - Push every node to the "node_path", if "node_path != nullptr".
* - Return the leaf you found during traversal.
*/
Node *current_node = this->_root;
return current_node;
}
template <typename K, typename V, bool U>
std::optional<typename ReturnValue<V, U>::type> BPlusTree<K, V, U>::get(const K key) const
{
/**
* Assignment (2): Implement a B+-Tree
*
* This method tries to find the value for a given key.
* The tree is a very generic data structure which can hold
* one value per key or multiple values per key. The specific
* variant is given by the template parameter U which is a bool
* and stands for Unique. True means: Return one value of type V;
* false means: Return a set of values of type V.
*
* Hints for implementation:
* - You have already implemented "locate_leaf(k)" which returns the
* leaf that may contain the searched key-value pair.
* - Every leaf node provides a method "index(k)" which returns the index
* of the key "k".
* - Every leaf node provides a method "leaf_key(i)" which returns the
* key at index "i".
* - Every leaf node provides a method "value(i)" which returns the value
* at index "i". The "value(i)" method will automatically pick the correct
* return type, depending on the U-template-parameter.
*
* Procedure:
* - Locate the leaf node that may contain the wanted key.
* - Check the leaf node: Is the wanted key available?
* - If yes: return the value of the key.
* - Otherwise return an empty result, using "return { };".
*/
return std::nullopt;
}
template <typename K, typename V, bool U>
std::optional<std::set<V>> BPlusTree<K, V, U>::get(const K key_from, const K key_to) const
{
/**
* Assignment (2): Implement a B+-Tree
*
* This method tries to find one or multiple values for a given
* range of keys.
* The tree is a very generic data structure which can hold
* one value per key or multiple values per key. The specific
* variant is given by the template parameter U which is a bool
* and stands for Unique. True means: Return one value of type V;
* false means: Return a set of values of type V.
*
* Hints for implementation:
* - You have already implemented "locate_leaf(k)" which returns the
* leaf that may contain the searched key-value pair.
* - Every node provides a method "right()" which returns a pointer
* to the right neighbour node.
* - Every node provides a method "size()" which returns the number of
* items that are stored in the node.
* - Every leaf node provides a method "index(k)" which returns the index
* of the key "k".
* - Every leaf node provides a method "leaf_key(i)" which returns the
* key at index "i".
* - Every leaf node provides a method "value(i)" which returns the value
* at index "i". The "value(i)" method will automatically pick the correct
* return type, depending on the U-template-parameter.
* - You can test whether it is a unique or non-unique tree, using
* "if constexpr(U) { code for unique... } else { core for non-unique... }.
* - Both containers std::set (https://en.cppreference.com/w/cpp/container/set)
* and std::optional (https://en.cppreference.com/w/cpp/utility/optional) may
* be helpful on compiler errors.
*
* Procedure:
* - Locate the leaf node that may contain the wanted key.
* - Add all keys that are equal or greater than the key "key_from"
* and equal or lesser than the key "key_to" to a set of values.
* - When the last key of the node matches that predicate, also
* take a look to the right neighbour using the "right()" method
* (and also the rights right,...).
*/
std::set<V> values;
return values;
}
template <typename K, typename V, bool U>
BPlusTreeNode<K, V, U> *BPlusTree<K, V, U>::insert_into_leaf(BPlusTreeNode<K, V, U> *leaf_node, const K key,
const V value)
{
/**
* Assignment (2): Implement a B+-Tree
*
* This method adds a value to a leaf node. The correct leaf node, key and
* value are all given. When inserting results in splitting the leaf,
* the pointer to the new created node is returned.
*
* Hints for implementation:
* - Every node provides a method "full()" which returns true, if there
* is no more place for a new item.
* - Every leaf node provides a method "index(k)" which returns the index
* of the key "k".
* - Every leaf node provides a method "leaf_key(i)" which returns the
* key at index "i".
* - Every leaf node provides a method "insert_value(i, v, k)" which adds
* a key-value pair (k,v) to the leaf at index i.
* - The tree has a method "this->split_leaf_node(l)" which splits the leaf
* node l and returns a pointer to the new node.
* - You can test whether it is a unique or non-unique tree, using
* "if constexpr(U) { code for unique... } else { core for non-unique... }.
*
* Procedure:
* - Check if the leaf node already contains the key
* - If yes and the tree is non-unique: add the value to the list of values
* in the node and return a "nullptr".
* - If yey and the tree is unique: Just return a "nullptr".
* - If the key is not in the node, check for space for a new (key,value) pair.
* - If the node is not full, insert the new pair and return a "nullptr"
* - Otherwise, we have to split the node. Splitting will create a new leaf node,
* the new right neighbour of the given leaf node.
* - After splitting, we have enough space to insert the pair. Check whether the key
* should take place in the given leaf or the new leaf, created on splitting:
* When the key is lower than the first key of the new leaf, the key should be insert
* into the given leaf, otherwise in the new leaf.
* - After splitting, return the pointer to the new leaf.
*/
return nullptr;
}
} // namespace beedb::index::bplustree

View File

@ -0,0 +1,294 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "index/return_value.h"
#include <array>
#include <config.h>
#include <cstdint>
#include <cstring>
#include <utility>
namespace beedb::index::bplustree
{
using size_type = std::size_t;
template <typename K, typename V, bool U> class BPlusTreeNode;
template <typename K, typename V, bool U> struct BPlusTreeNodeHeader
{
size_type size = 0;
bool is_leaf;
BPlusTreeNode<K, V, U> *right = nullptr;
BPlusTreeNodeHeader(const bool is_leaf_) : is_leaf(is_leaf_)
{
}
};
template <typename K, typename V, bool U> struct BPlusTreeLeafNode
{
static constexpr size_type max_items = (Config::b_plus_tree_page_size - sizeof(BPlusTreeNodeHeader<K, V, U>)) /
(sizeof(K) + sizeof(typename ReturnValue<V, U>::type));
std::array<K, BPlusTreeLeafNode::max_items> keys;
std::array<typename ReturnValue<V, U>::type, BPlusTreeLeafNode::max_items> values;
};
template <typename K, typename V, bool U> struct BPlusTreeInnerNode
{
static constexpr size_type max_keys =
(Config::b_plus_tree_page_size - sizeof(BPlusTreeNodeHeader<K, V, U>) - sizeof(BPlusTreeNode<K, V, U> *)) /
(sizeof(K) + sizeof(BPlusTreeInnerNode<K, V, U> *));
static constexpr size_type max_separators = max_keys + 1;
std::array<K, BPlusTreeInnerNode::max_keys> keys;
std::array<BPlusTreeNode<K, V, U> *, BPlusTreeInnerNode::max_separators> separators;
};
template <typename K, typename V, bool U> class BPlusTreeNode
{
public:
BPlusTreeNode(const bool is_leaf) : _header(is_leaf)
{
}
~BPlusTreeNode();
inline bool is_leaf() const
{
return _header.is_leaf;
}
inline bool is_inner() const
{
return is_leaf() == false;
}
inline size_type size() const
{
return _header.size;
}
inline void size(const size_type size)
{
_header.size = size;
}
inline BPlusTreeNode<K, V, U> *right()
{
return _header.right;
}
inline bool has_right() const
{
return _header.right != nullptr;
}
inline void right(BPlusTreeNode<K, V, U> *right)
{
_header.right = right;
}
inline typename ReturnValue<V, U>::type &value(const size_type index)
{
return _leaf_node.values[index];
}
inline BPlusTreeNode<K, V, U> *separator(const size_type index)
{
return _inner_node.separators[index];
}
inline void separator(const size_type index, BPlusTreeNode<K, V, U> *separator)
{
_inner_node.separators[index] = separator;
}
inline K leaf_key(const size_type index)
{
return _leaf_node.keys[index];
}
inline K inner_key(const size_type index)
{
return _inner_node.keys[index];
}
inline bool is_full() const
{
const size_type max_size =
is_leaf() ? BPlusTreeLeafNode<K, V, U>::max_items : BPlusTreeInnerNode<K, V, U>::max_keys;
return size() >= max_size;
}
size_type index(const K key);
BPlusTreeNode<K, V, U> *child(const K key);
void insert_separator(const size_type index, BPlusTreeNode<K, V, U> *separator, const K key);
void insert_value(const size_type index, const V value, const K key);
void copy(BPlusTreeNode *other, const size_type from_index, const size_type count);
std::pair<std::size_t, std::size_t> size_include_children();
std::pair<std::size_t, std::size_t> count_children();
private:
BPlusTreeNodeHeader<K, V, U> _header;
union {
BPlusTreeInnerNode<K, V, U> _inner_node;
BPlusTreeLeafNode<K, V, U> _leaf_node;
};
};
template <typename K, typename V, bool U> BPlusTreeNode<K, V, U>::~BPlusTreeNode()
{
if (is_leaf() == false)
{
for (size_type i = 0; i < size(); i++)
{
delete _inner_node.separators[i];
}
}
}
template <typename K, typename V, bool U> size_type BPlusTreeNode<K, V, U>::index(const K key)
{
auto keys = is_leaf() ? _leaf_node.keys.begin() : _inner_node.keys.begin();
auto iterator = std::lower_bound(keys, keys + size(), key);
return std::distance(keys, iterator);
}
template <typename K, typename V, bool U> BPlusTreeNode<K, V, U> *BPlusTreeNode<K, V, U>::child(const K key)
{
std::int32_t low = 0, high = size() - 1;
while (low <= high)
{
const std::int32_t mid = (low + high) / 2;
if (_inner_node.keys[mid] <= key)
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
return _inner_node.separators[high + 1];
}
template <typename K, typename V, bool U>
void BPlusTreeNode<K, V, U>::insert_separator(const size_type index, BPlusTreeNode<K, V, U> *separator, const K key)
{
if (index < size())
{
const size_type offset = size() - index;
std::memmove(&_inner_node.keys[index + 1], &_inner_node.keys[index], offset * sizeof(K));
std::memmove(&_inner_node.separators[index + 2], &_inner_node.separators[index + 1],
offset * sizeof(BPlusTreeNode<K, V, U> *));
}
_inner_node.keys[index] = key;
_inner_node.separators[index + 1] = separator;
_header.size++;
}
template <typename K, typename V, bool U>
void BPlusTreeNode<K, V, U>::insert_value(const size_type index, const V value, const K key)
{
if (index < size())
{
const size_type offset = size() - index;
std::memmove(&_leaf_node.keys[index + 1], &_leaf_node.keys[index], offset * sizeof(K));
std::memmove(static_cast<void *>(&_leaf_node.values[index + 1]), &_leaf_node.values[index],
offset * sizeof(typename ReturnValue<V, U>::type));
}
_leaf_node.keys[index] = key;
if constexpr (U)
{
_leaf_node.values[index] = value;
}
else
{
new (&_leaf_node.values[index]) typename ReturnValue<V, U>::type();
_leaf_node.values[index].insert(value);
}
_header.size++;
}
template <typename K, typename V, bool U>
void BPlusTreeNode<K, V, U>::copy(BPlusTreeNode<K, V, U> *other, const size_type from_index, const size_type count)
{
if (is_leaf())
{
std::memcpy(&other->_leaf_node.keys[0], &_leaf_node.keys[from_index], count * sizeof(K));
std::memcpy(static_cast<void *>(&other->_leaf_node.values[0]), &_leaf_node.values[from_index],
count * sizeof(typename ReturnValue<V, U>::type));
}
else
{
std::memcpy(&other->_inner_node.keys[0], &_inner_node.keys[from_index], count * sizeof(K));
std::memcpy(&other->_inner_node.separators[1], &_inner_node.separators[from_index + 1],
count * sizeof(BPlusTreeNode<K, V, U> *));
}
}
template <typename K, typename V, bool U>
std::pair<std::size_t, std::size_t> BPlusTreeNode<K, V, U>::size_include_children()
{
if (is_leaf())
{
return {0u, size()};
}
std::size_t leaf_sizes = 0, inner_sizes = 0;
for (auto i = 0u; i <= size(); i++)
{
BPlusTreeNode<K, V, U> *child = _inner_node.separators[i];
const auto child_size = child->size_include_children();
inner_sizes += child_size.first;
leaf_sizes += child_size.second;
}
return {inner_sizes, leaf_sizes};
}
template <typename K, typename V, bool U> std::pair<std::size_t, std::size_t> BPlusTreeNode<K, V, U>::count_children()
{
if (is_leaf())
{
return {0u, 0u};
}
if (_inner_node.separators[0]->is_leaf())
{
return {0u, size() + 1u};
}
std::size_t leaf_children = 0, inner_children = 0;
for (auto i = 0u; i <= size(); i++)
{
BPlusTreeNode<K, V, U> *child = _inner_node.separators[i];
const auto child_size = child->count_children();
inner_children += child_size.first;
leaf_children += child_size.second;
}
return {inner_children + size(), leaf_children};
}
} // namespace beedb::index::bplustree

View File

@ -0,0 +1,72 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "b_plus_tree.h"
#include <index/index_interface.h>
#include <index/non_unique_index_interface.h>
#include <index/range_index_interface.h>
namespace beedb::index::bplustree
{
/**
* B+-Tree implementation for non-unique (key,value) pairs.
* Can store multiple values for each key.
* Supports range queries.
*/
class NonUniqueBPlusTreeIndex : public IndexInterface, public NonUniqueIndexInterface, public RangeIndexInterface
{
public:
NonUniqueBPlusTreeIndex(const std::string &name) : IndexInterface(name)
{
}
virtual ~NonUniqueBPlusTreeIndex() = default;
virtual bool supports_range() const
{
return true;
}
virtual bool is_unique() const
{
return false;
}
virtual void put(const std::int64_t key, disk::Page::page_id page_pointer)
{
_tree.put(key, page_pointer);
}
virtual std::optional<std::set<disk::Page::page_id>> get(const std::int64_t key) const
{
return _tree.get(key);
}
virtual std::optional<std::set<disk::Page::page_id>> get(const std::int64_t key_from, const std::int64_t key_to)
{
return _tree.get(key_from, key_to);
}
private:
BPlusTree<std::int64_t, disk::Page::page_id, false> _tree;
};
} // namespace beedb::index::bplustree

View File

@ -0,0 +1,71 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "b_plus_tree.h"
#include <index/index_interface.h>
#include <index/range_index_interface.h>
#include <index/unique_index_interface.h>
namespace beedb::index::bplustree
{
/**
* B+-Tree implementation for unique (key,value) pairs.
* Supports range queries.
*/
class UniqueBPlusTreeIndex : public IndexInterface, public UniqueIndexInterface, public RangeIndexInterface
{
public:
UniqueBPlusTreeIndex(const std::string &name) : IndexInterface(name)
{
}
virtual ~UniqueBPlusTreeIndex() = default;
virtual bool supports_range() const
{
return true;
}
virtual bool is_unique() const
{
return true;
}
virtual void put(const std::int64_t key, disk::Page::page_id page_pointer)
{
_tree.put(key, page_pointer);
}
virtual std::optional<disk::Page::page_id> get(const std::int64_t key) const
{
return _tree.get(key);
}
virtual std::optional<std::set<disk::Page::page_id>> get(const std::int64_t key_from, const std::int64_t key_to)
{
return _tree.get(key_from, key_to);
}
private:
BPlusTree<std::int64_t, disk::Page::page_id, true> _tree;
};
} // namespace beedb::index::bplustree

View File

@ -0,0 +1,60 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "b_plus_tree/non_unique_b_plus_tree_index.h"
#include "b_plus_tree/unique_b_plus_tree_index.h"
#include "index_interface.h"
#include "type.h"
#include <memory>
namespace beedb::index
{
class IndexFactory
{
public:
/**
* Builds an empty index.
*
* @param name Name for the index.
* @param type The index type identifies the underlying data structure like BTree, Hashtable, ...
* @param is_unique Identifies whether the index can hold multiple values for one key.
* @return Pointer to the in-memory index structure.
*/
static std::shared_ptr<IndexInterface> new_index(const std::string &name, const Type type, const bool is_unique)
{
if (type == Type::BTree)
{
if (is_unique)
{
return std::make_shared<bplustree::UniqueBPlusTreeIndex>(name);
}
else
{
return std::make_shared<bplustree::NonUniqueBPlusTreeIndex>(name);
}
}
return {};
}
};
} // namespace beedb::index

View File

@ -0,0 +1,70 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <disk/page.h>
namespace beedb::index
{
/**
* The index interface offers an API for multiple indices, whether
* they are range-indices, support multiple values for one key.
*/
class IndexInterface
{
public:
IndexInterface(const std::string &name) : _name(name)
{
}
virtual ~IndexInterface() = default;
/**
* @return True, if the index supports just one value per key.
*/
virtual bool is_unique() const = 0;
/**
* @return True, if the index supports range queries (like B+Trees).
*/
virtual bool supports_range() const = 0;
/**
* Stores a (Key,Page) pair in the index.
*
* @param key Key for lookups.
* @param page_id Value.
*/
virtual void put(const std::int64_t key, disk::Page::page_id page_id) = 0;
/**
* @return Name of the index.
*/
const std::string &name() const
{
return _name;
}
private:
const std::string _name;
};
} // namespace beedb::index

View File

@ -0,0 +1,49 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <cstdint>
#include <disk/page.h>
#include <optional>
#include <set>
namespace beedb::index
{
/**
* Interface for non-unique indices.
* The index can store multiple values per key.
*/
class NonUniqueIndexInterface
{
public:
NonUniqueIndexInterface() = default;
virtual ~NonUniqueIndexInterface() = default;
/**
* Lookup for all values of a key.
*
* @param key Key to lookup.
* @return All stored values for the key.
*/
virtual std::optional<std::set<disk::Page::page_id>> get(const std::int64_t key) const = 0;
};
} // namespace beedb::index

View File

@ -0,0 +1,49 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <cstdint>
#include <disk/page.h>
#include <optional>
#include <set>
namespace beedb::index
{
/**
* Interface for range indices.
* The index can lookup a range of keys for range-queries.
*/
class RangeIndexInterface
{
public:
/**
* Lookup of a key-range.
*
* @param key_from From key.
* @param key_to To key.
* @return All values for the given key-range.
*/
virtual std::optional<std::set<disk::Page::page_id>> get(const std::int64_t key_from,
const std::int64_t key_to) = 0;
};
} // namespace beedb::index

View File

@ -0,0 +1,38 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <optional>
#include <set>
namespace beedb::index
{
template <typename Value, bool Unique> struct ReturnValue
{
using type = Value;
};
template <typename Value> struct ReturnValue<Value, false>
{
using type = std::set<Value>;
};
} // namespace beedb::index

39
src/include/index/type.h Normal file
View File

@ -0,0 +1,39 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <regex>
namespace beedb::index
{
/**
* Possible index types.
*/
enum Type
{
None,
BTree,
Hashtable,
Skiplist,
Bitmap /*, some more like: SkipList,... */
};
} // namespace beedb::index

View File

@ -0,0 +1,48 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <cstdint>
#include <disk/page.h>
#include <optional>
namespace beedb::index
{
/**
* Interface for unique indices.
* The index can store only one value per key.
*/
class UniqueIndexInterface
{
public:
UniqueIndexInterface() = default;
virtual ~UniqueIndexInterface() = default;
/**
* Lookup for a value for a given key.
*
* @param key Key to lookup.
* @return The stored value or an empty optional.
*/
virtual std::optional<disk::Page::page_id> get(const std::int64_t key) const = 0;
};
} // namespace beedb::index

View File

@ -0,0 +1,49 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#include "custom_command_interface.h"
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
namespace beedb::io::command
{
class Commander
{
public:
Commander() = default;
~Commander() = default;
bool has_command_prefix(const std::string &input);
std::optional<Query> create_query(const std::string &input);
void register_command(const std::string &name, std::unique_ptr<CustomCommandInterface> &&command)
{
_registered_commands[name] = std::move(command);
}
private:
std::unordered_map<std::string, std::unique_ptr<CustomCommandInterface>> _registered_commands;
};
} // namespace beedb::io::command

View File

@ -0,0 +1,38 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "io/executor.h"
#include <string>
#include <vector>
namespace beedb::io::command
{
class CustomCommandInterface
{
public:
virtual ~CustomCommandInterface() = default;
virtual std::optional<Query> execute(const std::string &input) = 0;
virtual std::string help_str() = 0;
};
} // namespace beedb::io::command

View File

@ -0,0 +1,97 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "custom_command_interface.h"
namespace beedb::io::command
{
class ShowCommand final : public CustomCommandInterface
{
public:
virtual ~ShowCommand() = default;
virtual std::optional<Query> execute(const std::string &parameters) override;
virtual std::string help_str() override
{
return std::string(_help_str);
};
private:
static constexpr auto _help_str = "Syntax> :show [tables,indices,columns]{1}";
};
class ExplainCommand final : public CustomCommandInterface
{
public:
virtual ~ExplainCommand() = default;
virtual std::optional<Query> execute(const std::string &input) override;
virtual std::string help_str() override
{
return std::string(_help_str);
};
private:
static constexpr auto _help_str = "Syntax> :explain [plan,graph]? <SQL-Statement>";
};
class SetCommand final : public CustomCommandInterface
{
public:
SetCommand(Config &config) : _config(config)
{
}
virtual ~SetCommand() = default;
virtual std::optional<Query> execute(const std::string &input) override;
virtual std::string help_str() override
{
return std::string(_help_str);
};
private:
static constexpr auto _help_str = "Syntax> :set <Argument Name> <Numerical Value>";
private:
Config &_config;
};
class GetCommand final : public CustomCommandInterface
{
public:
GetCommand(Config &config) : _config(config)
{
}
virtual ~GetCommand() = default;
virtual std::optional<Query> execute(const std::string &input) override;
virtual std::string help_str() override
{
return std::string(_help_str);
};
private:
static constexpr auto _help_str = "Syntax> :get [<Argument Name>]?";
private:
Config &_config;
};
} // namespace beedb::io::command

136
src/include/io/executor.h Normal file
View File

@ -0,0 +1,136 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <chrono>
#include <database.h>
#include <plan/physical/plan.h>
#include <string>
namespace beedb::io
{
/**
* @brief The Query struct contains the query-string and some parameters
* that influence the execution of a query, e.g. printing the logical plan
*/
struct Query
{
enum ExplainLevel
{
None,
Plan,
Graph
};
const std::string query_string;
ExplainLevel explain = None;
};
/**
* Wrapper for time and performance statistics, measured
* while query execution.
*/
class ExecutionResult
{
public:
ExecutionResult() : _is_successful(false)
{
}
ExecutionResult(const std::chrono::milliseconds build_time, const std::chrono::milliseconds execution_time,
const std::size_t evicted_pages)
: _is_successful(true), _build_ms(build_time), _execution_ms(execution_time), _evicted_pages(evicted_pages)
{
}
~ExecutionResult() = default;
std::chrono::milliseconds build_time() const
{
return _build_ms;
}
std::chrono::milliseconds execution_time() const
{
return _execution_ms;
}
std::size_t evicted_pages() const
{
return _evicted_pages;
}
bool is_successful() const
{
return _is_successful;
}
private:
const bool _is_successful = false;
const std::chrono::milliseconds _build_ms{};
const std::chrono::milliseconds _execution_ms{};
const std::size_t _evicted_pages = 0u;
};
/**
* Executes queries and query plans.
*/
class Executor
{
public:
Executor(Database &database) : _database(database)
{
}
~Executor() = default;
ExecutionResult execute(const Query &query, std::function<void(const table::Schema &)> schema_callback,
std::function<void(const table::Tuple &)> tuple_callback);
ExecutionResult execute(const Query &query, std::function<void(const table::Tuple &)> tuple_callback)
{
return execute(
query, [](const table::Schema &) {}, tuple_callback);
}
ExecutionResult execute(const Query &query)
{
return execute(query, [](const table::Tuple &) {});
}
ExecutionResult execute(plan::physical::Plan &plan, std::function<void(const table::Schema &)> schema_callback,
std::function<void(const table::Tuple &)> tuple_callback);
ExecutionResult execute(plan::physical::Plan &plan, std::function<void(const table::Tuple &)> tuple_callback)
{
return execute(
plan, [](const table::Schema &) {}, tuple_callback);
}
ExecutionResult execute(plan::physical::Plan &plan)
{
return execute(plan, [](const table::Tuple &) {});
}
protected:
Database &_database;
};
} // namespace beedb::io

View File

@ -0,0 +1,42 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "executor.h"
namespace beedb::io
{
/**
* Parses files for SQL-queries and executes them.
*/
class FileExecutor : private Executor
{
public:
FileExecutor(Database &database) : Executor(database)
{
}
virtual ~FileExecutor() = default;
void import_file(const std::string &file_name);
};
} // namespace beedb::io

View File

@ -0,0 +1,42 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "executor.h"
namespace beedb::io
{
/**
* Executes SQL-queries and prints the result to the console.
*/
class PrintingExecutor : protected Executor
{
public:
PrintingExecutor(Database &database) : Executor(database)
{
}
virtual ~PrintingExecutor() = default;
void execute(const Query &query);
};
} // namespace beedb::io

View File

@ -0,0 +1,89 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <cstdint>
#include <ostream>
#include <table/schema.h>
#include <table/tuple.h>
#include <util/text_table.h>
#include <vector>
namespace beedb::io
{
/**
* Formats the result of a query, given by schema and set of tuples.
*/
class ResultOutputFormatter
{
friend std::ostream &operator<<(std::ostream &stream, const ResultOutputFormatter &result_output_formatter);
public:
/**
* Set the header for the output.
*
* @param schema Schema for the header.
*/
void header(const table::Schema &schema);
/**
* Add a set of tuples to the result.
* @param tuples Set of tuples.
*/
void push_back(const std::vector<table::Tuple> &tuples);
/**
* Add a single tuple to the result.
* @param tuple
*/
void push_back(const table::Tuple &tuple);
/**
* Clear the formatter.
*/
inline void clear()
{
_table.clear();
}
/**
* @return True, when no tuple as added.
*/
inline bool empty() const
{
return _table.empty();
}
/**
* @return Number of added tuples.
*/
inline std::size_t count() const
{
return _count_tuples;
}
private:
util::TextTable _table;
std::size_t _count_tuples = 0u;
};
} // namespace beedb::io

View File

@ -0,0 +1,46 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "printing_executor.h"
namespace beedb::io
{
/**
* Provides a console to the user.
* The console is blocking and takes every input
* from the keyboard.
*/
class UserConsole : protected PrintingExecutor
{
public:
UserConsole(Database &database) : PrintingExecutor(database)
{
}
virtual ~UserConsole() = default;
/**
* Waits and executes user input from keyboard.
*/
void wait_for_input();
};
} // namespace beedb::io

View File

@ -0,0 +1,94 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include "parser/query_parser.h"
#include <memory>
// hsql:
#include <SQLParser.h>
namespace beedb::parser
{
class HSQLParser : public QueryParser
{
public:
HSQLParser(const std::string &query);
virtual ~HSQLParser() = default;
protected:
private:
// implementation of parser functionality (see QueryParser class):
const SelectExpression extractSELECT_impl() const override;
const std::optional<FromExpression> extractFROM_impl() const override;
const std::optional<WhereExpression> extractWHERE_impl() const override;
const std::optional<GroupByExpression> extractGROUPBY_impl() const override;
const std::optional<OrderByExpression> extractORDERBY_impl() const override;
const std::optional<LimitExpression> extractLIMIT_impl() const override;
virtual const std::optional<CreateTableExpression> extractCREATE_TABLE_impl() const override;
virtual const std::optional<CreateIndexExpression> extractCREATE_INDEX_impl() const override;
virtual const std::optional<InsertExpression> extractINSERT_impl() const override;
virtual const UpdateExpression extractUPDATE_impl() const override;
/// HELPER FUNCTIONS:
/**
* @brief extract_From_impl evaluates a TableRef expression.
* Due to how joins are represented, this has to be done recursively.
*
* This function has side-effects (on fexp param).
* @param fexp holds the result (and more)
* @param from_expr the expression to evaluate
*/
std::unique_ptr<FromDescr> extractFROM_impl(const hsql::TableRef *table_ref) const;
/**
* @brief extract_predicate converts a predicate hsql::Expr* to a predicate in the database internal representation.
* Is called recursively for logical connected sub-predicates. Makes use of the build_operand helper, defined below.
* @param expression
* @return a std::variant<> of pointers
*/
expression::Predicate extract_predicate(const hsql::Expr *expression) const;
/**
* @brief build_operand extracts operands of an atom
* @param expression
* @return a std::variant<> of values
*/
const expression::Operand build_operand(const hsql::Expr *expression) const;
/**
* @brief build_attribute is a helper that builds a expression::Attribute.
* This is done by checking for existence of alias, table references etc.
* @param h_expr
* @return
*/
expression::Attribute build_attribute(const hsql::Expr *h_expr) const;
expression::AttributeOrigin determine_function_type(const std::string &function_name) const;
// hsql specific members:
hsql::SQLParserResult _hsql_result;
const hsql::SQLStatement *_hsql_statement;
};
} // namespace beedb::parser

View File

@ -0,0 +1,325 @@
/*------------------------------------------------------------------------------*
* Architecture & Implementation of DBMS *
*------------------------------------------------------------------------------*
* Copyright 2020 Databases and Information Systems Group TU Dortmund *
* Visit us at *
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
* *
* Authors (alphabetical list): *
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
*------------------------------------------------------------------------------*
*/
#pragma once
#include <assert.h>
#include <optional>
#include <string>
#include <functional>
#include <iostream>
#include <tuple>
#include <type_traits>
#include <variant>
#include <vector>
#include "expression/predicate.h"
#include <exception/exception.h>
#include <index/type.h>
#include <table/type.h>
namespace beedb::parser
{
using SelectExpression = beedb::expression::Attributes;
/**
* @brief The FromExpression struct is used by the QueryParser class to
* represent expressions of tables, joins (and subqueries?).
*/
using Alias = std::optional<std::string>;
using TableDescr = std::pair<std::string, Alias>;
struct FromDescr;
using JoinDescr = std::tuple<std::unique_ptr<FromDescr>, std::unique_ptr<FromDescr>, expression::Predicate>;
using CrossProductDescr = std::vector<std::unique_ptr<FromDescr>>;
// struct SELECTDescr;
struct FromDescr
{
std::variant<TableDescr, JoinDescr, CrossProductDescr /*,SELECTDescr**/> descr;
};
static inline void print_structure(const std::variant<TableDescr, JoinDescr, CrossProductDescr> &from,
std::string pfx = "")
{
// std::cout << pfx;
switch (from.index())
{
case 0:
std::cout << "TableDescr" << std::endl;
break;
case 1: {
std::cout << "JoinDescr with ";
const auto &pred = std::get<expression::Predicate>(std::get<JoinDescr>(from));
std::string pred_str;
std::visit(expression::LogicalConnective::TermStringifier{pred_str}, pred);
std::cout << pred_str << std::endl;
print_structure(std::get<0>(std::get<JoinDescr>(from))->descr, pfx + "\t");
print_structure(std::get<1>(std::get<JoinDescr>(from))->descr, pfx + "\t");
}
break;
case 2:
std::cout << "CrossProductDescr" << std::endl;
for (const auto &el : std::get<CrossProductDescr>(from))
{
print_structure(el->descr, pfx + "\t");
}
default:
return;
}
}
struct FromExpression
{
std::unique_ptr<FromDescr> from_description;
std::vector<std::reference_wrapper<expression::Predicate>> predicates() const
{
auto predicates = std::vector<std::reference_wrapper<expression::Predicate>>();
std::visit(PredicateExtractor{predicates}, from_description->descr);
return predicates;
}
std::vector<std::reference_wrapper<TableDescr>> tables() const
{
auto attributes = std::vector<std::reference_wrapper<TableDescr>>();
std::visit(TableExtractor{attributes}, from_description->descr);
return attributes;
}
struct PredicateExtractor
{
// helper struct for visitor pattern
std::vector<std::reference_wrapper<expression::Predicate>> &predicates;
// depending on the variant type,
// c++ picks the appropiate call operator:
void operator()(TableDescr &)
{ /* do nothing */
}
void operator()(JoinDescr &join_description)
{
predicates.push_back(std::get<2>(join_description));
std::visit(PredicateExtractor{predicates}, std::get<0>(join_description)->descr);
std::visit(PredicateExtractor{predicates}, std::get<1>(join_description)->descr);
}
void operator()(CrossProductDescr &descriptions)
{
for (const auto &description : descriptions)
{
std::visit(PredicateExtractor{predicates}, description->descr);
}
}
};
struct TableExtractor
{
// helper struct for visitor pattern
std::vector<std::reference_wrapper<TableDescr>> &attributes;
// depending on the variant type,
// c++ picks the appropiate call operator:
void operator()(TableDescr &table_description)
{
attributes.push_back(table_description);
}
void operator()(JoinDescr &join_description)
{
std::visit(TableExtractor{attributes}, std::get<0>(join_description)->descr);
std::visit(TableExtractor{attributes}, std::get<1>(join_description)->descr);
}
void operator()(CrossProductDescr &cross_product_description)
{
for (const auto &description : cross_product_description)
{
std::visit(TableExtractor{attributes}, description->descr);
}
}
};
};
using WhereExpression = expression::Predicate;
using GroupByExpression = expression::Attributes;
using OrderByExpression = expression::Attributes;
struct LimitExpression
{
std::uint64_t limit;
std::uint64_t offset;
};
struct ColumnExpression
{
std::string column_name;
table::Type::Id type_id;
std::uint16_t length;
bool is_null;
};
struct CreateTableExpression
{
std::string table_name;
bool if_not_exists;
std::vector<ColumnExpression> column_expressions;
};
struct CreateIndexExpression
{
std::string table_name;
std::string column_name;
std::string index_name;
bool is_unique;
index::Type type;
bool if_not_exists;
};
struct InsertExpression
{
std::string table_name;
std::vector<std::string> column_names;
std::vector<std::vector<std::optional<expression::Operand>>> values_rows;
};
struct UpdateExpression
{
std::optional<FromExpression> from;
std::vector<std::pair<expression::Attribute, expression::Operand>> updates;
std::optional<WhereExpression> where;
};
/**
* @brief The QueryParser class offers methods that extract information for logical plan creation.
* This interface can be subclassed for different types of parsers.
* Creation of the logical plan is solely based on this interface and therefore be done without knowing the
* frontend.
*/
class QueryParser
{
public:
QueryParser(const std::string &query); // simply stores the query string
virtual ~QueryParser() = default;
// this enum provides information about the type of query
enum class QueryType
{
SELECT = 0,
UNION,
CREATE_TABLE,
CREATE_INDEX,
UPDATE,
INSERT,
DELETE,
DROP, // => "type of statements that we support"
UNSUPPORTED // => "a given query is a statement we do not support"
};
QueryType type() const;
const SelectExpression extractSELECT() const
{
assert(_query_type == QueryType::SELECT);
// the implementation is guarded to prevent calling extractSelect on non-selection queries.
return extractSELECT_impl();
}
const std::optional<FromExpression> extractFROM() const
{
assert(_query_type == QueryType::SELECT);
return extractFROM_impl();
}
const std::optional<WhereExpression> extractWHERE() const
{
assert(_query_type == QueryType::SELECT);
return extractWHERE_impl();
}
const std::optional<GroupByExpression> extractGROUPBY() const
{
assert(_query_type == QueryType::SELECT);
return extractGROUPBY_impl();
}
const std::optional<OrderByExpression> extractORDERBY() const
{
assert(_query_type == QueryType::SELECT);
return extractORDERBY_impl();
}
const std::optional<LimitExpression> extractLIMIT() const
{
assert(_query_type == QueryType::SELECT);
return extractLIMIT_impl();
}
const std::optional<CreateTableExpression> extractCREATE_TABLE() const
{
assert(_query_type == QueryType::CREATE_TABLE);
return extractCREATE_TABLE_impl();
}
const std::optional<CreateIndexExpression> extractCREATE_INDEX() const
{
assert(_query_type == QueryType::CREATE_INDEX);
return extractCREATE_INDEX_impl();
}
const std::optional<InsertExpression> extractINSERT() const
{
assert(_query_type == QueryType::INSERT);
return extractINSERT_impl();
}
const UpdateExpression extractUPDATE() const
{
assert(_query_type == QueryType::UPDATE);
return extractUPDATE_impl();
}
protected:
static bool operands_should_swap(const beedb::expression::Operand &lhs, const beedb::expression::Operand &rhs);
virtual const SelectExpression extractSELECT_impl() const = 0;
virtual const std::optional<FromExpression> extractFROM_impl() const = 0;
virtual const std::optional<expression::Predicate> extractWHERE_impl() const = 0;
virtual const std::optional<GroupByExpression> extractGROUPBY_impl() const = 0;
virtual const std::optional<OrderByExpression> extractORDERBY_impl() const = 0;
virtual const std::optional<LimitExpression> extractLIMIT_impl() const = 0;
virtual const std::optional<CreateTableExpression> extractCREATE_TABLE_impl() const = 0;
virtual const std::optional<CreateIndexExpression> extractCREATE_INDEX_impl() const = 0;
virtual const std::optional<InsertExpression> extractINSERT_impl() const = 0;
virtual const UpdateExpression extractUPDATE_impl() const = 0;
/// Members:
protected:
const std::string &_query;
std::optional<QueryType> _query_type = std::nullopt; // supposed to be filled in the constructor of sub-classes
};
} // namespace beedb::parser

Some files were not shown because too many files have changed in this diff Show More