diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
index 29c27eaf536434d2f870fc111ca00f5febec1327..083090b871f199ea2ef24728a7f46fd9b862527c 100644
--- a/include/CMakeLists.txt
+++ b/include/CMakeLists.txt
@@ -35,6 +35,8 @@ set(libcaosdb_INCL
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/logging.h
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/message_code.h
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/protobuf_helper.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/result_table.h
+    #${CMAKE_CURRENT_SOURCE_DIR}/caosdb/result_set.h
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/status_code.h
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction.h
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction_handler.h
diff --git a/include/caosdb/result_table.h b/include/caosdb/result_table.h
new file mode 100644
index 0000000000000000000000000000000000000000..393924ca94f3f10499c9028fa13f699d583315f0
--- /dev/null
+++ b/include/caosdb/result_table.h
@@ -0,0 +1,124 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2022 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2022 IndiScale GmbH <info@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef CAOSDB_RESULT_TABLE_H
+#define CAOSDB_RESULT_TABLE_H
+
+#include "caosdb/value.h"                   // for Value
+#include <iterator>                         // for iterator, next
+#include <memory>  // for unique_ptr
+#include <string>  // for string
+
+namespace caosdb::transaction {
+using caosdb::entity::Value;
+
+class ResultTableImpl;
+
+class ResultTableColumnImpl;
+
+class ResultTableRowImpl;
+
+class ResultTableRow {
+public:
+  [[nodiscard]] auto GetValue(const std::string &column) const noexcept -> Value;
+  friend class ResultTable;
+  explicit ResultTableRow(std::unique_ptr<ResultTableRowImpl> delegate);
+
+private:
+  std::unique_ptr<ResultTableRowImpl> delegate;
+};
+
+class ResultTableColumn {
+public:
+  /**
+   * Get the name of the column.
+   */
+  [[nodiscard]] auto GetName() const noexcept -> const std::string &;
+
+  friend class ResultTable;
+  explicit ResultTableColumn(std::unique_ptr<ResultTableColumnImpl> delegate);
+
+private:
+  std::unique_ptr<ResultTableColumnImpl> delegate;
+};
+
+class ResultTable {
+  class HeaderIterator;
+  class RowIterator;
+
+public:
+  /**
+   * Number of rows.
+   *
+   * The header is not counted as a row.
+   */
+  [[nodiscard]] auto size() const noexcept -> int;
+  /**
+   * Get the header of this table, i.e. the list of columns.
+   */
+  [[nodiscard]] auto GetHeader() const noexcept -> HeaderIterator;
+  /**
+   * Get the data rows, i.e. the actual data.
+   */
+  [[nodiscard]] auto GetRows() const noexcept -> RowIterator;
+
+  friend class ResultTableImpl;
+
+private:
+  class HeaderIterator : std::iterator<std::output_iterator_tag, ResultTableColumn> {
+  public:
+    explicit HeaderIterator(const ResultTable *result_table, int index = 0);
+    HeaderIterator(const HeaderIterator &other);
+    auto operator*() const -> const ResultTableColumn &;
+    auto operator++() -> HeaderIterator &;
+    auto operator++(int) -> HeaderIterator;
+    auto operator!=(const HeaderIterator &rhs) const -> bool;
+    auto size() const noexcept -> int;
+    auto begin() const -> HeaderIterator;
+    auto end() const -> HeaderIterator;
+
+  private:
+    int current_index = 0;
+    const ResultTable *result_table;
+  };
+
+  class RowIterator : std::iterator<std::output_iterator_tag, ResultTableRow> {
+  public:
+    explicit RowIterator(const ResultTable *result_table, int index = 0);
+    RowIterator(const RowIterator &other);
+    auto operator*() const -> const ResultTableRow &;
+    auto operator++() -> RowIterator &;
+    auto operator++(int) -> RowIterator;
+    auto operator!=(const RowIterator &rhs) const -> bool;
+    auto size() const noexcept -> int;
+    auto begin() const -> RowIterator;
+    auto end() const -> RowIterator;
+
+  private:
+    int current_index = 0;
+    const ResultTable *result_table;
+  };
+
+  explicit ResultTable(std::unique_ptr<ResultTableImpl> delegate);
+  std::unique_ptr<ResultTableImpl> delegate;
+};
+
+} // namespace caosdb::transaction
+#endif
diff --git a/include/caosdb/transaction.h b/include/caosdb/transaction.h
index cc889413a3d377c8798dac6cdb471610bb2a6b44..19c3a97dacc2385eef17965935bce88d9c1088c2 100644
--- a/include/caosdb/transaction.h
+++ b/include/caosdb/transaction.h
@@ -30,7 +30,9 @@
 #include "caosdb/logging.h"                 // for CAOSDB_LOG_ERR...
 #include "caosdb/protobuf_helper.h"         // for get_arena
 #include "caosdb/status_code.h"             // for StatusCode
+#include "caosdb/result_table.h"            // for ResultTable
 #include "caosdb/transaction_status.h"      // for StatusCode
+#include "caosdb/value.h"                   // for Value
 #include <algorithm>                        // for max
 #include <future>                           // for async, future
 #include <google/protobuf/arena.h>          // for Arena
@@ -166,6 +168,7 @@
 namespace caosdb::transaction {
 using caosdb::entity::Entity;
 using caosdb::entity::FileDescriptor;
+using caosdb::entity::Value;
 using caosdb::entity::v1::EntityResponse;
 using caosdb::entity::v1::EntityTransactionService;
 using caosdb::entity::v1::FileDownloadRequest;
@@ -185,62 +188,6 @@ using TransactionResponseCase = caosdb::entity::v1::TransactionResponse::Transac
 using caosdb::utility::get_arena;
 using google::protobuf::Arena;
 
-class ResultTableImpl;
-
-class ResultTableColumnImpl;
-
-class ResultTableColumn {
-public:
-  /**
-   * Get the name of the column.
-   */
-  [[nodiscard]] auto GetName() const noexcept -> const std::string &;
-
-  friend class ResultTable;
-  explicit ResultTableColumn(std::unique_ptr<ResultTableColumnImpl> delegate);
-private:
-  std::unique_ptr<ResultTableColumnImpl> delegate;
-};
-
-class ResultTable {
-  class HeaderIterator;
-
-public:
-  /**
-   * Number of rows.
-   *
-   * The header is not counted as a row.
-   */
-  [[nodiscard]] auto size() const noexcept -> int;
-  /**
-   * Get the header of this table, i.e. the list of columns.
-   */
-  [[nodiscard]] auto GetHeader() const noexcept -> const HeaderIterator;
-
-  friend class ResultTableImpl;
-
-private:
-  class HeaderIterator : std::iterator<std::output_iterator_tag, ResultTableColumn> {
-  public:
-    explicit HeaderIterator(const ResultTable *result_table, int index = 0);
-    HeaderIterator(const HeaderIterator &other);
-    auto operator*() const -> const ResultTableColumn &;
-    auto operator++() -> HeaderIterator &;
-    auto operator++(int) -> HeaderIterator;
-    auto operator!=(const HeaderIterator &rhs) const -> bool;
-    auto size() const noexcept -> int;
-    auto begin() const -> HeaderIterator;
-    auto end() const -> HeaderIterator;
-
-  private:
-    int current_index = 0;
-    const ResultTable *result_table;
-  };
-
-  explicit ResultTable(std::unique_ptr<ResultTableImpl> delegate);
-  std::unique_ptr<ResultTableImpl> delegate;
-};
-
 class Transaction;
 
 /**
diff --git a/include/caosdb/value.h b/include/caosdb/value.h
index a92847a82d3cd15ad2dda61e64c6843b99ac6d75..c89bd226bbc618b46d985eb087c540d1c1f35e56 100644
--- a/include/caosdb/value.h
+++ b/include/caosdb/value.h
@@ -297,6 +297,9 @@ public:
     this->wrapped->CopyFrom(*value.GetProtoValue());
   }
   explicit inline Value(ProtoValue *wrapped) : ScalarProtoMessageWrapper<ProtoValue>(wrapped) {}
+  explicit inline Value(const ProtoValue &value) : ScalarProtoMessageWrapper<ProtoValue>() {
+    this->wrapped->CopyFrom(value);
+  }
   explicit inline Value(const std::string &value) : ScalarProtoMessageWrapper<ProtoValue>() {
     this->wrapped->mutable_scalar_value()->set_string_value(value);
   }
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f64bc7671cbe142390ca5439916dfbddd3660294..b4f28930ce2402c2c3a7ea03c994b8a07e492a58 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -27,6 +27,8 @@ set(libcaosdb_SRC
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/connection.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/configuration.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/protobuf_helper.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/result_table.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/result_table_impl.h
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction_handler.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/utility.cpp
@@ -45,6 +47,5 @@ IF(BUILD_ACM)
          ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/acm/user_impl.h
          )
 ENDIF()
-
 # pass variable to parent scope
 set(libcaosdb_SRC ${libcaosdb_SRC}  PARENT_SCOPE)
diff --git a/src/caosdb/result_table.cpp b/src/caosdb/result_table.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f6fa223bbde47d64944d3fd1aa464beb01dc3e56
--- /dev/null
+++ b/src/caosdb/result_table.cpp
@@ -0,0 +1,184 @@
+
+/*
+ * This file is a part of the CaosDB Project.
+ * Copyright (C) 2021-2022 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2021-2022 IndiScale GmbH <info@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+#include "caosdb/result_table.h"               // for ResultTable, ResultTab...
+#include "caosdb/entity/v1/main.pb.h"          // for SelectQueryResult, Sel...
+#include "caosdb/protobuf_helper.h"            // for ScalarProtoMessageWrapper
+#include "caosdb/result_table_impl.h"          // for ResultTableImpl, Resul...
+#include "caosdb/value.h"                      // for Value
+#include <algorithm>                           // for max
+#include <google/protobuf/repeated_field.h> // IWYU pragma: keep for RepeatedPtrField
+#include <memory>                              // for unique_ptr
+#include <string>                              // for string, operator==
+#include <utility>                             // for move
+#include <vector>                              // for vector
+// IWYU pragma: no_include "net/proto2/public/repeated_field.h"
+
+namespace caosdb::transaction {
+using caosdb::entity::Value;
+using ProtoSelectQueryResult = caosdb::entity::v1::SelectQueryResult;
+using ProtoSelectQueryHeader = caosdb::entity::v1::SelectQueryHeader;
+using ProtoSelectQueryColumn = caosdb::entity::v1::SelectQueryColumn;
+using ProtoSelectQueryRow = caosdb::entity::v1::SelectQueryRow;
+using caosdb::utility::ScalarProtoMessageWrapper;
+
+ResultTableRowImpl::ResultTableRowImpl(ProtoSelectQueryResult *table, int row)
+  : header(*table->mutable_header()), row(*table->mutable_data_rows(row)) {}
+
+auto ResultTableRowImpl::GetColumnIndex(const std::string &column_name) const noexcept -> int {
+  for (int i = 0; i < this->header.columns_size(); i++) {
+    if (this->header.columns(i).name() == column_name) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+auto ResultTableRowImpl::GetValue(const std::string &column) const noexcept -> Value {
+  const auto column_index = GetColumnIndex(column);
+  if (column_index == -1) {
+    // NULL_VALUE
+    return {};
+  }
+  Value result(this->row.cells(column_index));
+  return result;
+}
+
+ResultTableRow::ResultTableRow(std::unique_ptr<ResultTableRowImpl> delegate)
+  : delegate(std::move(delegate)) {}
+
+auto ResultTableRow::GetValue(const std::string &column) const noexcept -> Value {
+  return this->delegate->GetValue(column);
+}
+
+ResultTableColumnImpl::ResultTableColumnImpl(ProtoSelectQueryColumn *column)
+  : ScalarProtoMessageWrapper<ProtoSelectQueryColumn>(column) {}
+
+ResultTableColumn::ResultTableColumn(std::unique_ptr<ResultTableColumnImpl> delegate)
+  : delegate(std::move(delegate)) {}
+
+auto ResultTableColumn::GetName() const noexcept -> const std::string & {
+  return this->delegate->wrapped->name();
+}
+
+auto ResultTableImpl::create(ProtoSelectQueryResult *select_result)
+  -> std::unique_ptr<ResultTable> {
+  return std::unique_ptr<ResultTable>(
+    new ResultTable(std::unique_ptr<ResultTableImpl>(new ResultTableImpl(select_result))));
+}
+
+ResultTableImpl::ResultTableImpl(ProtoSelectQueryResult *result_table)
+  : ScalarProtoMessageWrapper<ProtoSelectQueryResult>(result_table) {
+  for (auto &column : *this->wrapped->mutable_header()->mutable_columns()) {
+    this->columns.emplace_back(
+      std::unique_ptr<ResultTableColumnImpl>(new ResultTableColumnImpl(&column)));
+  }
+  for (int i = 0; i < this->wrapped->data_rows_size(); i++) {
+    this->rows.emplace_back(
+      std::unique_ptr<ResultTableRowImpl>(new ResultTableRowImpl(this->wrapped, i)));
+  }
+}
+
+ResultTable::ResultTable(std::unique_ptr<ResultTableImpl> delegate)
+  : delegate(std::move(delegate)) {}
+
+auto ResultTable::size() const noexcept -> int { return this->delegate->wrapped->data_rows_size(); }
+
+auto ResultTable::GetRows() const noexcept -> RowIterator { return RowIterator(this, 0); }
+
+ResultTable::RowIterator::RowIterator(const ResultTable *result_table_param, int index)
+  : current_index(index), result_table(result_table_param) {}
+
+ResultTable::RowIterator::RowIterator(const RowIterator &other)
+  : current_index(other.current_index), result_table(other.result_table) {}
+
+auto ResultTable::RowIterator::size() const noexcept -> int {
+  return this->result_table->delegate->wrapped->data_rows_size();
+}
+
+auto ResultTable::RowIterator::operator*() const -> const ResultTableRow & {
+  return this->result_table->delegate->rows.at(this->current_index);
+}
+
+auto ResultTable::RowIterator::operator++() -> RowIterator & {
+  current_index++;
+  return *this;
+}
+
+auto ResultTable::RowIterator::operator++(int) -> RowIterator {
+  RowIterator tmp(*this);
+  operator++();
+  return tmp;
+}
+
+auto ResultTable::RowIterator::operator!=(const RowIterator &rhs) const -> bool {
+  return this->current_index != rhs.current_index;
+}
+
+auto ResultTable::RowIterator::begin() const -> RowIterator {
+  return RowIterator(this->result_table);
+}
+
+auto ResultTable::RowIterator::end() const -> RowIterator {
+  return RowIterator(this->result_table, size());
+}
+
+auto ResultTable::GetHeader() const noexcept -> HeaderIterator {
+  return HeaderIterator(this, 0);
+}
+
+ResultTable::HeaderIterator::HeaderIterator(const ResultTable *result_table_param, int index)
+  : current_index(index), result_table(result_table_param) {}
+
+ResultTable::HeaderIterator::HeaderIterator(const HeaderIterator &other)
+  : current_index(other.current_index), result_table(other.result_table) {}
+
+auto ResultTable::HeaderIterator::size() const noexcept -> int {
+  return this->result_table->delegate->wrapped->header().columns_size();
+}
+
+auto ResultTable::HeaderIterator::operator*() const -> const ResultTableColumn & {
+  return this->result_table->delegate->columns.at(this->current_index);
+}
+
+auto ResultTable::HeaderIterator::operator++() -> HeaderIterator & {
+  current_index++;
+  return *this;
+}
+
+auto ResultTable::HeaderIterator::operator++(int) -> HeaderIterator {
+  HeaderIterator tmp(*this);
+  operator++();
+  return tmp;
+}
+
+auto ResultTable::HeaderIterator::operator!=(const HeaderIterator &rhs) const -> bool {
+  return this->current_index != rhs.current_index;
+}
+
+auto ResultTable::HeaderIterator::begin() const -> HeaderIterator {
+  return HeaderIterator(this->result_table);
+}
+
+auto ResultTable::HeaderIterator::end() const -> HeaderIterator {
+  return HeaderIterator(this->result_table, size());
+}
+
+} // namespace caosdb::transaction
diff --git a/src/caosdb/result_table_impl.h b/src/caosdb/result_table_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..3450a68cf7ae0638d42d3ea1c79fd9d181a3eaab
--- /dev/null
+++ b/src/caosdb/result_table_impl.h
@@ -0,0 +1,84 @@
+/*
+ * This file is a part of the CaosDB Project.
+ * Copyright (C) 2021-2022 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2021-2022 IndiScale GmbH <info@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef CAOSDB_RESULT_TABLE_IMPL_H
+#define CAOSDB_RESULT_TABLE_IMPL_H
+
+#include "caosdb/transaction.h"
+#include "caosdb/entity/v1/main.grpc.pb.h"                         // for EntityTransac...
+#include "caosdb/entity/v1/main.pb.h"                              // for TransactionRe...
+#include "caosdb/file_transmission/download_request_handler.h"     // Download...
+#include "caosdb/file_transmission/file_reader.h"                  // for path
+#include "caosdb/file_transmission/register_file_upload_handler.h" // for RegisterFileUploadHandler
+#include "caosdb/file_transmission/upload_request_handler.h"       // Upload...
+#include "caosdb/logging.h"                                        // for CAOSDB_LOG_FATAL
+#include "caosdb/protobuf_helper.h"                                // for ProtoMessageWrapper
+#include "caosdb/status_code.h"                                    // for StatusCode
+#include "caosdb/transaction_handler.h"                            // for EntityTransactionHandler
+#include <algorithm>                                               // for max
+#include <filesystem>                                              // for operator<<, path
+#include <future>                                                  // for async, future
+#include <google/protobuf/arena.h>                                 // for Arena
+#include <grpc/grpc.h>                                             // for gpr_timespec
+#include <map>                                                     // for map, operator!=
+#include <memory>                                                  // for unique_ptr
+#include <random>                                                  // for mt19937, rand...
+#include <system_error>                                            // for std::system_error
+#include <utility>                                                 // for move, pair
+
+namespace caosdb::transaction {
+using caosdb::entity::Value;
+using ProtoSelectQueryResult = caosdb::entity::v1::SelectQueryResult;
+using ProtoSelectQueryHeader = caosdb::entity::v1::SelectQueryHeader;
+using ProtoSelectQueryColumn = caosdb::entity::v1::SelectQueryColumn;
+using ProtoSelectQueryRow = caosdb::entity::v1::SelectQueryRow;
+using caosdb::utility::ScalarProtoMessageWrapper;
+
+class ResultTableRowImpl {
+  explicit ResultTableRowImpl(ProtoSelectQueryResult *table, int row);
+  [[nodiscard]] auto GetValue(const std::string &column) const noexcept -> Value;
+  [[nodiscard]] auto GetColumnIndex(const std::string &column) const noexcept -> int;
+  friend class ResultTableRow;
+  friend class ResultTableImpl;
+  ProtoSelectQueryHeader &header;
+  ProtoSelectQueryRow &row;
+};
+
+class ResultTableColumnImpl : public ScalarProtoMessageWrapper<ProtoSelectQueryColumn> {
+  explicit ResultTableColumnImpl(ProtoSelectQueryColumn *column);
+  friend class ResultTableColumn;
+  friend class ResultTableImpl;
+};
+
+class ResultTableImpl : public ScalarProtoMessageWrapper<ProtoSelectQueryResult> {
+  static auto create(ProtoSelectQueryResult *select_result) -> std::unique_ptr<ResultTable>;
+  ResultTableImpl();
+  explicit ResultTableImpl(ProtoSelectQueryResult *result_table);
+  std::vector<ResultTableColumn> columns;
+  std::vector<ResultTableRow> rows;
+
+  friend class ResultTable;
+  friend class ResultTable::HeaderIterator;
+  friend class ResultTableColumn;
+  friend auto ProcessSelectResponse(ProtoSelectQueryResult *select_result)
+    -> std::unique_ptr<ResultTable>;
+};
+
+} // namespace caosdb::transaction
+#endif
diff --git a/src/caosdb/transaction.cpp b/src/caosdb/transaction.cpp
index ca8ea2f984f443d0f13dfa50840d85fb03c567bd..5ea5496fc46e807f2be63057ae2aa0efed9f00ae 100644
--- a/src/caosdb/transaction.cpp
+++ b/src/caosdb/transaction.cpp
@@ -25,7 +25,9 @@
 #include "caosdb/file_transmission/register_file_upload_handler.h" // for RegisterFileUploadHandler
 #include "caosdb/file_transmission/upload_request_handler.h"       // Upload...
 #include "caosdb/logging.h"                                        // for CAOSDB_LOG_FATAL
-#include "caosdb/protobuf_helper.h"      // for ProtoMessageWrapper
+#include "caosdb/protobuf_helper.h"                                // for ProtoMessageWrapper
+#include "caosdb/result_table.h"                                   // for ResultTable
+#include "caosdb/result_table_impl.h"                              // for ResultTableImpl
 #include "caosdb/status_code.h"                                    // for StatusCode
 #include "caosdb/transaction_handler.h"                            // for EntityTransactionHandler
 #include <algorithm>                                               // for max
@@ -53,96 +55,12 @@ using RetrieveResponseCase = caosdb::entity::v1::RetrieveResponse::RetrieveRespo
 using RetrieveResponse = caosdb::entity::v1::RetrieveResponse;
 using ProtoEntity = caosdb::entity::v1::Entity;
 using ProtoSelectQueryResult = caosdb::entity::v1::SelectQueryResult;
-using ProtoSelectQueryColumn = caosdb::entity::v1::SelectQueryColumn;
 using caosdb::entity::v1::EntityRequest;
-using caosdb::utility::ScalarProtoMessageWrapper;
 
 using google::protobuf::Arena;
 using NextStatus = grpc::CompletionQueue::NextStatus;
 using RegistrationStatus = caosdb::entity::v1::RegistrationStatus;
 
-class ResultTableColumnImpl : public ScalarProtoMessageWrapper<ProtoSelectQueryColumn> {
-  explicit ResultTableColumnImpl(ProtoSelectQueryColumn *column);
-  friend class ResultTableColumn;
-  friend class ResultTableImpl;
-};
-
-ResultTableColumnImpl::ResultTableColumnImpl(ProtoSelectQueryColumn *column) : ScalarProtoMessageWrapper<ProtoSelectQueryColumn>(column) {};
-
-ResultTableColumn::ResultTableColumn(std::unique_ptr<ResultTableColumnImpl> delegate) : delegate(std::move(delegate)) {}
-
-auto ResultTableColumn::GetName() const noexcept -> const std::string & {
-  return this->delegate->wrapped->name();
-}
-
-class ResultTableImpl : public ScalarProtoMessageWrapper<ProtoSelectQueryResult> {
-  static auto create(ProtoSelectQueryResult *select_result) -> std::unique_ptr<ResultTable>;
-  ResultTableImpl();
-  explicit ResultTableImpl(ProtoSelectQueryResult *result_table);
-  std::vector<ResultTableColumn> columns;
-
-  friend class ResultTable;
-  friend class ResultTable::HeaderIterator;
-  friend class ResultTableColumn;
-  friend auto ProcessSelectResponse(ProtoSelectQueryResult *select_result) -> std::unique_ptr<ResultTable>;
-};
-
-auto ResultTableImpl::create(ProtoSelectQueryResult *select_result) -> std::unique_ptr<ResultTable> {
-  return std::unique_ptr<ResultTable>(new ResultTable(std::unique_ptr<ResultTableImpl>(new ResultTableImpl(select_result))));
-}
-
-ResultTableImpl::ResultTableImpl(ProtoSelectQueryResult *result_table) : ScalarProtoMessageWrapper<ProtoSelectQueryResult>(result_table) {
-  for (auto &column : *this->wrapped->mutable_header()->mutable_columns()) {
-    this->columns.emplace_back(std::unique_ptr<ResultTableColumnImpl>(new ResultTableColumnImpl(&column)));
-  }
-}
-
-ResultTable::ResultTable(std::unique_ptr<ResultTableImpl> delegate) : delegate(std::move(delegate)) {}
-
-auto ResultTable::size() const noexcept -> int {
-  // TODO
-  return 0;
-}
-
-auto ResultTable::GetHeader() const noexcept -> const HeaderIterator {
-  return HeaderIterator(this, 0);
-}
-
-ResultTable::HeaderIterator::HeaderIterator(const ResultTable *result_table_param, int index) : current_index(index), result_table(result_table_param) {}
-
-ResultTable::HeaderIterator::HeaderIterator(const HeaderIterator &other) : current_index(other.current_index), result_table(other.result_table) {}
-
-auto ResultTable::HeaderIterator::size() const noexcept -> int {
-  return this->result_table->delegate->wrapped->header().columns_size();
-}
-
-auto ResultTable::HeaderIterator::operator*() const -> const ResultTableColumn & {
-  return this->result_table->delegate->columns.at(this->current_index);
-}
-
-auto ResultTable::HeaderIterator::operator++() -> HeaderIterator & {
-  current_index++;
-  return *this;
-}
-
-auto ResultTable::HeaderIterator::operator++(int) -> HeaderIterator {
-  HeaderIterator tmp(*this);
-  operator++();
-  return tmp;
-}
-
-auto ResultTable::HeaderIterator::operator!=(const HeaderIterator &rhs) const -> bool {
-  return this->current_index != rhs.current_index;
-}
-
-auto ResultTable::HeaderIterator::begin() const -> HeaderIterator {
-  return HeaderIterator(this->result_table);
-}
-
-auto ResultTable::HeaderIterator::end() const -> HeaderIterator {
-  return HeaderIterator(this->result_table, size());
-}
-
 ResultSet::iterator::iterator(const ResultSet *result_set_param, int index)
   : current_index(index), result_set(result_set_param) {}