diff --git a/.gitignore b/.gitignore index c58fa5a01..631bd3755 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ GRTAGS GPATH GTAGS .gitmodules +.cache #*# diff --git a/src/observer/sql/executor/execute_stage.cpp b/src/observer/sql/executor/execute_stage.cpp index d1da254ef..4cda073e2 100644 --- a/src/observer/sql/executor/execute_stage.cpp +++ b/src/observer/sql/executor/execute_stage.cpp @@ -32,6 +32,7 @@ See the Mulan PSL v2 for more details. */ #include "sql/operator/predicate_operator.h" #include "sql/operator/delete_operator.h" #include "sql/operator/project_operator.h" +#include "sql/operator/update_operator.h" #include "sql/stmt/stmt.h" #include "sql/stmt/select_stmt.h" #include "sql/stmt/update_stmt.h" @@ -142,7 +143,7 @@ void ExecuteStage::handle_request(common::StageEvent *event) do_insert(sql_event); } break; case StmtType::UPDATE: { - //do_update((UpdateStmt *)stmt, session_event); + do_update(sql_event); } break; case StmtType::DELETE: { do_delete(sql_event); @@ -438,6 +439,33 @@ RC ExecuteStage::do_select(SQLStageEvent *sql_event) return rc; } +RC ExecuteStage::do_update(SQLStageEvent *sql_event) +{ + LOG_WARN("do update"); + Stmt *stmt = sql_event->stmt(); + SessionEvent *session_event = sql_event->session_event(); + + if (stmt == nullptr) { + LOG_WARN("cannot find statement"); + return RC::GENERIC_ERROR; + } + + UpdateStmt *update_stmt = (UpdateStmt *)stmt; + TableScanOperator scan_oper(update_stmt->table()); + PredicateOperator pred_oper(update_stmt->filter_stmt()); + pred_oper.add_child(&scan_oper); + UpdateOperator update_oper(update_stmt); + update_oper.add_child(&pred_oper); + + RC rc = update_oper.open(); + if (rc != RC::SUCCESS) { + session_event->set_response("FAILURE\n"); + } else { + session_event->set_response("SUCCESS\n"); + } + return rc; +} + RC ExecuteStage::do_help(SQLStageEvent *sql_event) { SessionEvent *session_event = sql_event->session_event(); diff --git a/src/observer/sql/executor/execute_stage.h b/src/observer/sql/executor/execute_stage.h index 9444bb0b8..2e03a1f82 100644 --- a/src/observer/sql/executor/execute_stage.h +++ b/src/observer/sql/executor/execute_stage.h @@ -48,6 +48,7 @@ class ExecuteStage : public common::Stage { RC do_insert(SQLStageEvent *sql_event); RC do_delete(SQLStageEvent *sql_event); RC do_drop_table(SQLStageEvent *sql_event); + RC do_update(SQLStageEvent *sql_event); protected: private: diff --git a/src/observer/sql/operator/update_operator.cpp b/src/observer/sql/operator/update_operator.cpp new file mode 100644 index 000000000..f61034d31 --- /dev/null +++ b/src/observer/sql/operator/update_operator.cpp @@ -0,0 +1,65 @@ +/* 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 wuxiaobai24 on 2022/6/27. +// + +#include "common/log/log.h" +#include "sql/operator/update_operator.h" +#include "storage/record/record.h" +#include "storage/common/table.h" +#include "sql/stmt/update_stmt.h" + +RC UpdateOperator::open() +{ + if (children_.size() != 1) { + LOG_WARN("delete 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; + } + + Table *table = update_stmt_->table(); + while (RC::SUCCESS == (rc = child->next())) { + Tuple *tuple = child->current_tuple(); + if (nullptr == tuple) { + LOG_WARN("failed to get current record: %s", strrc(rc)); + return rc; + } + + RowTuple *row_tuple = static_cast(tuple); + Record &record = row_tuple->record(); + auto attr_name = update_stmt_->attribute_name(); + auto value = update_stmt_->values(); + rc = table->update_record(nullptr, &record, attr_name, value); + if (rc != RC::SUCCESS) { + LOG_WARN("failed to delete record: %s", strrc(rc)); + return rc; + } + } + return RC::SUCCESS; +} + +RC UpdateOperator::next() +{ + return RC::RECORD_EOF; +} + +RC UpdateOperator::close() +{ + children_[0]->close(); + return RC::SUCCESS; +} diff --git a/src/observer/sql/operator/update_operator.h b/src/observer/sql/operator/update_operator.h new file mode 100644 index 000000000..5bc630d4b --- /dev/null +++ b/src/observer/sql/operator/update_operator.h @@ -0,0 +1,42 @@ +/* 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 wuxiaobai24 on 2022/10/6. +// + +#pragma once + +#include "sql/operator/operator.h" +#include "rc.h" + +class UpdateStmt; + +class UpdateOperator : public Operator +{ +public: + UpdateOperator(UpdateStmt *update_stmt) + : update_stmt_(update_stmt) + {} + + ~UpdateOperator() = default; + + RC open() override; + RC next() override; + RC close() override; + + Tuple * current_tuple() override { + return nullptr; + } + //int tuple_cell_num() const override + //RC tuple_cell_spec_at(int index, TupleCellSpec &spec) const override +private: + UpdateStmt *update_stmt_ = nullptr; +}; diff --git a/src/observer/sql/stmt/stmt.cpp b/src/observer/sql/stmt/stmt.cpp index 81185c1cc..62f909eee 100644 --- a/src/observer/sql/stmt/stmt.cpp +++ b/src/observer/sql/stmt/stmt.cpp @@ -14,9 +14,11 @@ See the Mulan PSL v2 for more details. */ #include "rc.h" #include "common/log/log.h" +#include "sql/parser/parse_defs.h" #include "sql/stmt/insert_stmt.h" #include "sql/stmt/delete_stmt.h" #include "sql/stmt/select_stmt.h" +#include "sql/stmt/update_stmt.h" RC Stmt::create_stmt(Db *db, const Query &query, Stmt *&stmt) { @@ -33,6 +35,9 @@ RC Stmt::create_stmt(Db *db, const Query &query, Stmt *&stmt) case SCF_SELECT: { return SelectStmt::create(db, query.sstr.selection, stmt); } + case SCF_UPDATE: { + return UpdateStmt::create(db, query.sstr.update, stmt); + } default: { LOG_WARN("unknown query command"); } diff --git a/src/observer/sql/stmt/update_stmt.cpp b/src/observer/sql/stmt/update_stmt.cpp index 89331f54c..313566b55 100644 --- a/src/observer/sql/stmt/update_stmt.cpp +++ b/src/observer/sql/stmt/update_stmt.cpp @@ -12,15 +12,67 @@ See the Mulan PSL v2 for more details. */ // Created by Wangyunlai on 2022/5/22. // +#include "common/log/log.h" #include "sql/stmt/update_stmt.h" +#include "sql/stmt/filter_stmt.h" +#include "storage/common/db.h" +#include "storage/common/table.h" -UpdateStmt::UpdateStmt(Table *table, Value *values, int value_amount) - : table_ (table), values_(values), value_amount_(value_amount) +UpdateStmt::UpdateStmt(Table *table, char *attribute_name, Value *values, FilterStmt *filter_stmt) + : table_(table), attribute_name_(attribute_name), values_(values), filter_stmt_(filter_stmt) {} -RC UpdateStmt::create(Db *db, const Updates &update, Stmt *&stmt) +UpdateStmt::~UpdateStmt() { - // TODO - stmt = nullptr; - return RC::INTERNAL; + if (nullptr != filter_stmt_) { + delete filter_stmt_; + filter_stmt_ = nullptr; + } +} + +RC UpdateStmt::create(Db *db, const Updates &update_sql, Stmt *&stmt) +{ + const char *table_name = update_sql.relation_name; + if (nullptr == db || nullptr == table_name) { + LOG_WARN("invalid argument. db=%p, table_name=%p", db, table_name); + return RC::INVALID_ARGUMENT; + } + + // check whether the table exists + Table *table = db->find_table(table_name); + if (nullptr == table) { + LOG_WARN("no such table. db = %s, table = %s", db->name(), table_name); + return RC::SCHEMA_TABLE_NOT_EXIST; + } + + // check the fields exist + const TableMeta &table_meta = table->table_meta(); + const FieldMeta *field_meta = table_meta.field(update_sql.attribute_name); + if (nullptr == field_meta) { + LOG_WARN("no such field. table=%s, field=%s", table_name, update_sql.attribute_name); + return RC::SCHEMA_FIELD_NOT_EXIST; + } + + // check the field type + if (field_meta->type() != update_sql.value.type) { + LOG_WARN("field type not match. field=%s, field_type=%d, value_type=%d", + field_meta->name(), field_meta->type(), update_sql.value.type); + return RC::SCHEMA_FIELD_TYPE_MISMATCH; + } + + std::unordered_map table_map; + table_map.insert(std::pair(std::string(table_name), table)); + + FilterStmt *filter_stmt = nullptr; + RC rc = FilterStmt::create(db, table, &table_map, + update_sql.conditions, update_sql.condition_num, filter_stmt); + if (rc != RC::SUCCESS) { + LOG_WARN("failed to create filter statement. rc=%d:%s", rc, strrc(rc)); + return rc; + } + Value *values = const_cast(&update_sql.value); + char *attribute_name = update_sql.attribute_name; + stmt = new UpdateStmt(table, attribute_name, values, filter_stmt); + + return RC::SUCCESS; } diff --git a/src/observer/sql/stmt/update_stmt.h b/src/observer/sql/stmt/update_stmt.h index ca566618d..4a71bf6fb 100644 --- a/src/observer/sql/stmt/update_stmt.h +++ b/src/observer/sql/stmt/update_stmt.h @@ -18,25 +18,32 @@ See the Mulan PSL v2 for more details. */ #include "sql/stmt/stmt.h" class Table; +class FilterStmt; class UpdateStmt : public Stmt { public: UpdateStmt() = default; - UpdateStmt(Table *table, Value *values, int value_amount); + UpdateStmt(Table *table, char *attribute_name, Value *values, FilterStmt *filter_stmt); + ~UpdateStmt() override; + StmtType type() const override { return StmtType::UPDATE; } public: static RC create(Db *db, const Updates &update_sql, Stmt *&stmt); public: Table *table() const {return table_;} Value *values() const { return values_; } - int value_amount() const { return value_amount_; } + char *attribute_name() const { return attribute_name_; } + + FilterStmt *filter_stmt() const { return filter_stmt_; } private: Table *table_ = nullptr; Value *values_ = nullptr; - int value_amount_ = 0; + char* attribute_name_ = nullptr; + [[maybe_unused]]int value_amount_ = 1; + FilterStmt *filter_stmt_ = nullptr; }; diff --git a/src/observer/storage/common/table.cpp b/src/observer/storage/common/table.cpp index b3715302b..8e9bfd298 100644 --- a/src/observer/storage/common/table.cpp +++ b/src/observer/storage/common/table.cpp @@ -731,6 +731,45 @@ RC Table::delete_record(Trx *trx, Record *record) return rc; } +RC Table::update_record(Trx *trx, Record *record, const char *attribute_name, const Value *value) +{ + // Update the record + const int normal_field_start_index = table_meta_.sys_field_num(); + for (int i = normal_field_start_index; i < table_meta_.field_num(); i++) { + const FieldMeta *field = table_meta_.field(i); + if (0 != strcmp(field->name(), attribute_name)) { + continue; + } + + if (field->type() != value->type) { + LOG_ERROR("Invalid value type. table name =%s, field name=%s, type=%d, but given=%d", + table_meta_.name(), + field->name(), + field->type(), + value->type); + return RC::SCHEMA_FIELD_TYPE_MISMATCH; + } + + size_t copy_len = field->len(); + if (field->type() == CHARS) { + const size_t data_len = strlen((const char *)value->data); + if (copy_len > data_len) { + copy_len = data_len + 1; + } + } + memcpy(record->data() + field->offset(), value->data, copy_len); + break; + } + RC rc = RC::SUCCESS; + if (trx != nullptr) { + // TODO: trx support update record + } else { + // TODO: update entry of indexes + rc = record_handler_->update_record(record); + } + return rc; +} + RC Table::commit_delete(Trx *trx, const RID &rid) { RC rc = RC::SUCCESS; diff --git a/src/observer/storage/common/table.h b/src/observer/storage/common/table.h index c487f4d00..0d4769f36 100644 --- a/src/observer/storage/common/table.h +++ b/src/observer/storage/common/table.h @@ -55,6 +55,8 @@ class Table { RC insert_record(Trx *trx, int value_num, const Value *values); RC update_record(Trx *trx, const char *attribute_name, const Value *value, int condition_num, const Condition conditions[], int *updated_count); + RC update_record(Trx *trx, Record *record); + RC update_record(Trx *trx, Record *record, const char *attribute_name, const Value *value); RC delete_record(Trx *trx, ConditionFilter *filter, int *deleted_count); RC delete_record(Trx *trx, Record *record);