diff --git a/src/observer/sql/executor/delete_operator.h b/src/observer/sql/executor/delete_operator.h index 6a4ac77261c4dd8e8f011be85d131003a5fc9e03..983229463af964e1db70f6b1eeeca664166988d9 100644 --- a/src/observer/sql/executor/delete_operator.h +++ b/src/observer/sql/executor/delete_operator.h @@ -35,6 +35,15 @@ public: Tuple * current_tuple() override { return nullptr; } + int tuple_cell_num() const override + { + return 0; + } + + RC tuple_cell_spec_at(int index, TupleCellSpec &spec) const override + { + return RC::NOTFOUND; + } private: DeleteStmt *delete_stmt_ = nullptr; }; diff --git a/src/observer/sql/executor/execute_stage.cpp b/src/observer/sql/executor/execute_stage.cpp index 0d830b68deec388cd67c239201700aed7511db5c..12479041039ec9a040a0f87af1d56bb94fa1675c 100644 --- a/src/observer/sql/executor/execute_stage.cpp +++ b/src/observer/sql/executor/execute_stage.cpp @@ -29,6 +29,7 @@ See the Mulan PSL v2 for more details. */ #include "sql/executor/table_scan_operator.h" #include "sql/executor/predicate_operator.h" #include "sql/executor/delete_operator.h" +#include "sql/executor/project_operator.h" #include "sql/stmt/stmt.h" #include "sql/stmt/select_stmt.h" #include "sql/stmt/update_stmt.h" @@ -216,6 +217,25 @@ void end_trx_if_need(Session *session, Trx *trx, bool all_right) } } +void print_tuple_header(std::ostream &os, const Operator &oper) +{ + const int cell_num = oper.tuple_cell_num(); + TupleCellSpec cell_spec; + for (int i = 0; i < cell_num; i++) { + oper.tuple_cell_spec_at(i, cell_spec); + if (i != 0) { + os << " | "; + } + + if (cell_spec.alias()) { + os << cell_spec.alias(); + } + } + + if (cell_num > 0) { + os << '\n'; + } +} void tuple_to_string(std::ostream &os, const Tuple &tuple) { TupleCell cell; @@ -249,17 +269,25 @@ RC ExecuteStage::do_select(SQLStageEvent *sql_event) Table *table = select_stmt->tables().front(); TableScanOperator table_scan_operator(table); - rc = table_scan_operator.open(); + PredicateOperator pred_oper(select_stmt->filter_stmt()); + pred_oper.add_child(&table_scan_operator); + ProjectOperator project_oper; + project_oper.add_child(&pred_oper); + for (const FieldDesc &field : select_stmt->query_fields()) { + project_oper.add_projection(field.table_, field.field_meta_); + } + rc = project_oper.open(); if (rc != RC::SUCCESS) { LOG_WARN("failed to open operator"); return rc; } std::stringstream ss; - while ((rc = table_scan_operator.next()) == RC::SUCCESS) { + print_tuple_header(ss, project_oper); + while ((rc = project_oper.next()) == RC::SUCCESS) { // get current record // write to response - Tuple * tuple = table_scan_operator.current_tuple(); + Tuple * tuple = project_oper.current_tuple(); if (nullptr == tuple) { rc = RC::INTERNAL; LOG_WARN("failed to get current record. rc=%s", strrc(rc)); @@ -272,9 +300,9 @@ RC ExecuteStage::do_select(SQLStageEvent *sql_event) if (rc != RC::RECORD_EOF) { LOG_WARN("something wrong while iterate operator. rc=%s", strrc(rc)); - table_scan_operator.close(); + project_oper.close(); } else { - rc = table_scan_operator.close(); + rc = project_oper.close(); } session_event->set_response(ss.str()); return rc; diff --git a/src/observer/sql/executor/operator.h b/src/observer/sql/executor/operator.h index 11dd64aa5cbb8849caaa268ce049861e49d38d27..16c3afde21956e298ae0b4bb86a058bd35383c7a 100644 --- a/src/observer/sql/executor/operator.h +++ b/src/observer/sql/executor/operator.h @@ -19,6 +19,7 @@ See the Mulan PSL v2 for more details. */ #include "sql/executor/tuple.h" class Record; +class TupleCellSpec; class Operator { @@ -33,11 +34,14 @@ public: virtual RC close() = 0; virtual Tuple * current_tuple() = 0; + virtual int tuple_cell_num() const = 0; + virtual RC tuple_cell_spec_at(int index, TupleCellSpec &spec) const = 0; void add_child(Operator *oper) { children_.push_back(oper); } + protected: std::vector children_; }; diff --git a/src/observer/sql/executor/predicate_operator.cpp b/src/observer/sql/executor/predicate_operator.cpp index efbb20ad6d8e348eb4aa38b9553d2e1a8f453290..9648250fe558df35bd9fe3f21230f8fedbd9582a 100644 --- a/src/observer/sql/executor/predicate_operator.cpp +++ b/src/observer/sql/executor/predicate_operator.cpp @@ -74,7 +74,7 @@ void get_cell(const RowTuple &tuple, const FilterItem &filter_item, TupleCell &c bool PredicateOperator::do_predicate(RowTuple &tuple) { - if (filter_stmt_ == nullptr) { + if (filter_stmt_ == nullptr || filter_stmt_->filter_units().empty()) { return true; } @@ -102,3 +102,12 @@ bool PredicateOperator::do_predicate(RowTuple &tuple) } return false; } + +int PredicateOperator::tuple_cell_num() const +{ + return children_[0]->tuple_cell_num(); +} +RC PredicateOperator::tuple_cell_spec_at(int index, TupleCellSpec &spec) const +{ + return children_[0]->tuple_cell_spec_at(index, spec); +} diff --git a/src/observer/sql/executor/predicate_operator.h b/src/observer/sql/executor/predicate_operator.h index 551848fba6e1d8a4be7d17bdba91de29527e7e6a..acc35398afa1b567e70778948abca3eefd8bb6b7 100644 --- a/src/observer/sql/executor/predicate_operator.h +++ b/src/observer/sql/executor/predicate_operator.h @@ -31,6 +31,8 @@ public: RC close() override; Tuple * current_tuple() override; + int tuple_cell_num() const override; + RC tuple_cell_spec_at(int index, TupleCellSpec &spec) const override; private: bool do_predicate(RowTuple &tuple); private: diff --git a/src/observer/sql/executor/project_operator.cpp b/src/observer/sql/executor/project_operator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..396a1c1c33d40c349243f9ad8e1f322893fd3bae --- /dev/null +++ b/src/observer/sql/executor/project_operator.cpp @@ -0,0 +1,62 @@ +/* Copyright (c) 2021 Xie Meiyi(xiemeiyi@hust.edu.cn) and OceanBase and/or its affiliates. All rights reserved. +miniob is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. */ + +// +// Created by WangYunlai on 2022/07/01. +// + +#include "common/log/log.h" +#include "sql/executor/project_operator.h" +#include "storage/common/record.h" +#include "storage/common/table.h" + +RC ProjectOperator::open() +{ + if (children_.size() != 1) { + LOG_WARN("project operator must has 1 child"); + return RC::INTERNAL; + } + + Operator *child = children_[0]; + RC rc = child->open(); + if (rc != RC::SUCCESS) { + LOG_WARN("failed to open child operator: %s", strrc(rc)); + return rc; + } + + return RC::SUCCESS; +} + +RC ProjectOperator::next() +{ + return children_[0]->next(); +} + +RC ProjectOperator::close() +{ + children_[0]->close(); + return RC::SUCCESS; +} +Tuple *ProjectOperator::current_tuple() +{ + tuple_.set_tuple(children_[0]->current_tuple()); + return &tuple_; +} + +void ProjectOperator::add_projection(const Table *table, const FieldMeta *field_meta) +{ + TupleCellSpec spec(table->name(), field_meta->name(), field_meta->name()); + tuple_.add_cell_spec(spec); +} + +RC ProjectOperator::tuple_cell_spec_at(int index, TupleCellSpec &spec) const +{ + return tuple_.cell_spec_at(index, spec); +} diff --git a/src/observer/sql/executor/project_operator.h b/src/observer/sql/executor/project_operator.h new file mode 100644 index 0000000000000000000000000000000000000000..0ac687d34512d36acbc524f3d3ee24f517e31eb7 --- /dev/null +++ b/src/observer/sql/executor/project_operator.h @@ -0,0 +1,44 @@ +/* Copyright (c) 2021 Xie Meiyi(xiemeiyi@hust.edu.cn) and OceanBase and/or its affiliates. All rights reserved. +miniob is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. */ + +// +// Created by WangYunlai on 2022/07/01. +// + +#pragma once + +#include "sql/executor/operator.h" +#include "rc.h" + +class ProjectOperator : public Operator +{ +public: + ProjectOperator() + {} + + virtual ~ProjectOperator() = default; + + void add_projection(const Table *table, const FieldMeta *field); // TODO how to handle the memory in tupleCellSpec? + + RC open() override; + RC next() override; + RC close() override; + + int tuple_cell_num() const override + { + return tuple_.cell_num(); + } + + RC tuple_cell_spec_at(int index, TupleCellSpec &spec) const override; + + Tuple * current_tuple() override; +private: + ProjectTuple tuple_; +}; diff --git a/src/observer/sql/executor/table_scan_operator.cpp b/src/observer/sql/executor/table_scan_operator.cpp index 3d407b75174923ddfb02d953c53032b543d03a84..c4354da1608d70d6a445573096679ceeb5c23cd9 100644 --- a/src/observer/sql/executor/table_scan_operator.cpp +++ b/src/observer/sql/executor/table_scan_operator.cpp @@ -47,3 +47,7 @@ Tuple * TableScanOperator::current_tuple() tuple_.set_record(¤t_record_); return &tuple_; } +RC TableScanOperator::tuple_cell_spec_at(int index, TupleCellSpec &spec) const +{ + return tuple_.cell_spec_at(index, spec); +} diff --git a/src/observer/sql/executor/table_scan_operator.h b/src/observer/sql/executor/table_scan_operator.h index 88eb3008635d99e4fbbe23ad23ff93b8f9c59bd0..19a3092c04f03e44887149fe6a46809c50b1ce06 100644 --- a/src/observer/sql/executor/table_scan_operator.h +++ b/src/observer/sql/executor/table_scan_operator.h @@ -36,6 +36,13 @@ public: RC close() override; Tuple * current_tuple() override; + + int tuple_cell_num() const override + { + return tuple_.cell_num(); + } + + RC tuple_cell_spec_at(int index, TupleCellSpec &spec) const override; private: Table *table_ = nullptr; RecordFileScanner record_scanner_; diff --git a/src/observer/sql/executor/tuple.h b/src/observer/sql/executor/tuple.h index 8ad6f887d445b1a9d8e79da9dcba7c0b787ce5f6..35afdca08127beff08478e0ed4c5929ebc5f193c 100644 --- a/src/observer/sql/executor/tuple.h +++ b/src/observer/sql/executor/tuple.h @@ -27,7 +27,50 @@ class Table; class TupleCellSpec { - +public: + TupleCellSpec() = default; + TupleCellSpec(const char *table_name, const char *field_name, const char *alias) + : table_name_(table_name), field_name_(field_name), alias_(alias) + {} + + void set_table_name(const char *table_name) + { + this->table_name_ = table_name; + } + + void set_field_name(const char *field_name) + { + this->field_name_ = field_name; + } + + void set_alias(const char *alias) + { + this->alias_ = alias; + } + const char *table_name() const + { + return table_name_; + } + const char *field_name() const + { + return field_name_; + } + const char *alias() const + { + return alias_; + } + + bool is_same_cell(const TupleCellSpec &other) const + { + return 0 == strcmp(this->table_name_, other.table_name_) && + 0 == strcmp(this->field_name_, other.field_name_); + } + +private: + // TODO table and field cannot describe all scenerio, should be expression + const char *table_name_ = nullptr; + const char *field_name_ = nullptr; + const char *alias_ = nullptr; }; class Tuple @@ -38,8 +81,9 @@ public: virtual int cell_num() const = 0; virtual RC cell_at(int index, TupleCell &cell) const = 0; + virtual RC find_cell(const TupleCellSpec &spec, TupleCell &cell) const = 0; - //virtual RC cell_spec_at(int index, TupleCellSpec &spec) const; + virtual RC cell_spec_at(int index, TupleCellSpec &spec) const = 0; }; class RowTuple : public Tuple @@ -82,14 +126,33 @@ public: return RC::SUCCESS; } - RC cell_spec_at(int index, TupleCellSpec &spec) const + RC find_cell(const TupleCellSpec &spec, TupleCell &cell) const override + { + const char *table_name = spec.table_name(); + if (0 != strcmp(table_name, table_->name())) { + return RC::NOTFOUND; + } + + const char *field_name = spec.field_name(); + for (int i = 0; i < fields_->size(); ++i) { + const FieldMeta &field_meta = (*fields_)[i]; + if (0 == strcmp(field_name, field_meta.name())) { + return cell_at(i, cell); + } + } + return RC::NOTFOUND; + } + + RC cell_spec_at(int index, TupleCellSpec &spec) const override { if (index < 0 || index >= fields_->size()) { LOG_WARN("invalid argument. index=%d", index); return RC::INVALID_ARGUMENT; } const FieldMeta &field_meta = (*fields_)[index]; - // TODO + spec.set_table_name(table_->name()); + spec.set_field_name(field_meta.name()); + spec.set_alias(field_meta.name()); return RC::SUCCESS; } @@ -112,7 +175,59 @@ private: class CompositeTuple : public Tuple { public: + int cell_num() const override; + RC cell_at(int index, TupleCell &cell) const = 0; private: + int cell_num_ = 0; std::vector tuples_; }; */ + +class ProjectTuple : public Tuple +{ +public: + ProjectTuple() = default; + + void set_tuple(Tuple *tuple) + { + this->tuple_ = tuple; + } + + void add_cell_spec(const TupleCellSpec &spec) + { + speces_.push_back(spec); + } + int cell_num() const override + { + return speces_.size(); + } + + RC cell_at(int index, TupleCell &cell) const override + { + if (index < 0 || index >= speces_.size()) { + return RC::GENERIC_ERROR; + } + if (tuple_ == nullptr) { + return RC::GENERIC_ERROR; + } + + const TupleCellSpec &spec = speces_[index]; // TODO better: add mapping between projection and raw tuple + return tuple_->find_cell(spec, cell); + } + + RC find_cell(const TupleCellSpec &spec, TupleCell &cell) const override + { + return tuple_->find_cell(spec, cell); + } + RC cell_spec_at(int index, TupleCellSpec &spec) const override + { + if (index < 0 || index >= speces_.size()) { + return RC::NOTFOUND; + } + spec = speces_[index]; + return RC::SUCCESS; + } +private: + std::vector speces_; + Tuple *tuple_ = nullptr; +}; diff --git a/src/observer/sql/stmt/select_stmt.h b/src/observer/sql/stmt/select_stmt.h index df4f91f8debc5e8aa7255dcd16f82aaecf21d008..6d8fa3c6a2f482eb5a83614edcae97529f7cea57 100644 --- a/src/observer/sql/stmt/select_stmt.h +++ b/src/observer/sql/stmt/select_stmt.h @@ -24,7 +24,7 @@ class FilterStmt; class Db; class Table; -// better to create a field class +// TODO better to create a field class struct FieldDesc { Table *table_ = nullptr; @@ -47,6 +47,7 @@ public: public: const std::vector &tables() const { return tables_; } + const std::vector &query_fields() const { return query_fields_; } FilterStmt *filter_stmt() const { return filter_stmt_; } private: