/** * Copyright (c) 2021 OceanBase * OceanBase CE is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * 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 PubL v2 for more details. */ #define USING_LOG_PREFIX SHARE #include "share/ob_core_table_proxy.h" #include #include "lib/container/ob_array_helper.h" #include "lib/container/ob_array_iterator.h" #include "lib/mysqlclient/ob_mysql_result.h" #include "lib/string/ob_sql_string.h" #include "lib/time/ob_time_utility.h" #include "lib/mysqlclient/ob_mysql_proxy.h" #include "inner_table/ob_inner_table_schema.h" #include "share/ob_debug_sync.h" #include "lib/timezone/ob_time_convert.h" #include "share/ob_tenant_id_schema_version.h" namespace oceanbase { using namespace common; using namespace common::sqlclient; namespace share { int ObCoreTableProxy::Row::init(const int64_t row_id, ObCoreTableProxy &kv_proxy, const common::ObIArray &cells) { // allow init twice reset(); int ret = OB_SUCCESS; if (row_id < 0 || !kv_proxy.is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(row_id), K(kv_proxy)); } else { row_id_ = row_id; kv_proxy_ = &kv_proxy; if (OB_FAIL(extend_cell_array(cells.count()))) { LOG_WARN("extend cell array failed", K(ret)); } else { cell_cnt_ = 0; FOREACH_CNT(c, cells) { cells_[cell_cnt_++] = *c; } if (cell_cnt_ > 0) { std::sort(cells_, cells_ + cell_cnt_); } inited_ = true; } } return ret; } int ObCoreTableProxy::Row::get_int(const char *name, int64_t &value) const { int ret = OB_SUCCESS; Cell *cell = NULL; if (!inited_) { ret = OB_NOT_INIT; LOG_WARN("not init", K(ret)); } else if (NULL == name) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KP(name)); } else if (OB_FAIL(get_cell(name, cell))) { // return NULL value for not found if (OB_ENTRY_NOT_EXIST == ret) { ret = OB_ERR_NULL_VALUE; } else { LOG_WARN("find cell failed", K(ret), K(name)); } } else if (NULL == cell) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL cell", K(ret), K(name)); } else if (NULL == cell->value_.ptr()) { ret = OB_ERR_NULL_VALUE; } else { char *endptr = NULL; value = strtoll(cell->value_.ptr(), &endptr, 0); if (cell->value_.empty() || '\0' != *endptr) { ret = OB_INVALID_DATA; LOG_WARN("cell not int value", K(ret), "cell", *cell); } } return ret; } int ObCoreTableProxy::Row::get_uint(const char *name, uint64_t &value) const { int ret = OB_SUCCESS; Cell *cell = NULL; if (!inited_) { ret = OB_NOT_INIT; LOG_WARN("not init", K(ret)); } else if (NULL == name) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KP(name)); } else if (OB_FAIL(get_cell(name, cell))) { // return NULL value for not found if (OB_ENTRY_NOT_EXIST == ret) { ret = OB_ERR_NULL_VALUE; } else { LOG_WARN("find cell failed", K(ret), K(name)); } } else if (NULL == cell) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL cell", K(ret), K(name)); } else if (NULL == cell->value_.ptr()) { ret = OB_ERR_NULL_VALUE; } else { char *endptr = NULL; value = strtoull(cell->value_.ptr(), &endptr, 0); if (cell->value_.empty() || '\0' != *endptr) { ret = OB_INVALID_DATA; LOG_WARN("cell not int value", K(ret), "cell", *cell); } } return ret; } int ObCoreTableProxy::Row::get_varchar(const char *name, ObString &value) const { int ret = OB_SUCCESS; Cell *cell = NULL; if (!inited_) { ret = OB_NOT_INIT; LOG_WARN("not init", K(ret)); } else if (NULL == name) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KP(name)); } else if (OB_FAIL(get_cell(name, cell))) { // return NULL value for not found if (OB_ENTRY_NOT_EXIST == ret) { ret = OB_ERR_NULL_VALUE; } else { LOG_WARN("find cell failed", K(ret), K(name)); } } else if (NULL == cell) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL cell", K(ret), K(name)); } else if (NULL == cell->value_.ptr()) { ret = OB_ERR_NULL_VALUE; } else { value = cell->value_; } return ret; } int ObCoreTableProxy::Row::get_timestamp(const char *name, const common::ObTimeZoneInfo *tz_info, int64_t &value) const { int ret = OB_SUCCESS; Cell *cell = NULL; const char *special_column = "gmt_modified"; ObTimeConvertCtx cvrt_ctx(tz_info, true); if (!inited_) { ret = OB_NOT_INIT; LOG_WARN("not init", K(ret)); } else if (NULL == name) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KP(name)); } else if (strncmp(special_column, name, strlen(name))) { // gmt_modified is special treatment, get modify_time_us of __all_core_table const char *change_to_column = "modify_time_us"; if (OB_FAIL(get_int(change_to_column, value))) { LOG_WARN("get gmt_modified fail", K(ret), K(name), K(value)); } } else if (OB_FAIL(get_cell(name, cell))) { // return NULL value for not found if (OB_ENTRY_NOT_EXIST == ret) { ret = OB_ERR_NULL_VALUE; } else { LOG_WARN("find cell failed", K(ret), K(name)); } } else if (NULL == cell) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL cell", K(ret), K(name)); } else if (NULL == cell->value_.ptr()) { ret = OB_ERR_NULL_VALUE; } else if (OB_FAIL(ObTimeConverter::str_to_datetime(cell->value_, cvrt_ctx, value, NULL))){ ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid timestamp format", K(ret), "datetime_str", cell->value_, K(value)); } return ret; } int ObCoreTableProxy::Row::get_bool(const char *name, bool &value) const { int ret = OB_SUCCESS; int64_t int_val = 0; if (!inited_) { ret = OB_NOT_INIT; LOG_WARN("not init", K(ret)); } else if (NULL == name) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KP(name)); } else if (OB_FAIL(get_int(name, int_val))) { if (OB_ERR_NULL_VALUE != ret) { LOG_WARN("get_int failed", K(name), K(ret)); } } else { value = int_val; } return ret; } int ObCoreTableProxy::Row::get_cell(const char *name, ObCoreTableProxy::Cell *&cell) const { cell = NULL; int ret = OB_SUCCESS; if (!inited_) { ret = OB_NOT_INIT; LOG_WARN("not init", K(ret)); } else if (NULL == name) { LOG_WARN("invalid argument", K(ret), K(name)); } else if (OB_FAIL(get_cell(ObString::make_string(name), cell))) { if (OB_ENTRY_NOT_EXIST != ret) { LOG_WARN("get cell failed", K(ret), K(name)); } } return ret; } int ObCoreTableProxy::Row::get_cell(const ObString &name, ObCoreTableProxy::Cell *&cell) const { cell = NULL; int ret = OB_SUCCESS; if (!inited_) { ret = OB_NOT_INIT; LOG_WARN("not init", K(ret)); } else if (NULL == name.ptr()) { LOG_WARN("invalid argument", K(ret), K(name)); } else if (cell_cnt_ <= 0 || NULL == cells_) { ret = OB_ENTRY_NOT_EXIST; // do nothing for empty row } else { Cell find_cell; find_cell.name_ = name; cell = std::lower_bound(cells_, cells_ + cell_cnt_, find_cell); if (cell == (cells_ + cell_cnt_) || cell->name_ != find_cell.name_) { ret = OB_ENTRY_NOT_EXIST; cell = NULL; } } return ret; } int ObCoreTableProxy::Row::extend_cell_array(const int64_t cnt) { int ret = OB_SUCCESS; // called in init() func, do not check inited_ flag. if (cnt < 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(cnt)); } else { if (cnt > cell_cnt_) { Cell *new_cells = static_cast(kv_proxy_->allocator_.alloc(sizeof(Cell) * cnt)); if (NULL == new_cells) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("alloc cell array failed", K(ret), "size", sizeof(Cell) * cnt); } else { for (int64_t i = 0; i < cnt; ++i) { if (i < cell_cnt_) { new (&new_cells[i]) Cell(cells_[i]); cells_[i].~Cell(); } else { new (&new_cells[i]) Cell(); } } if (NULL != cells_) { kv_proxy_->allocator_.free(cells_); } cells_ = new_cells; } } } return ret; } int ObCoreTableProxy::Row::update_cell(const Cell &cell) { int ret = OB_SUCCESS; Cell new_cell; if (!inited_) { ret = OB_NOT_INIT; LOG_WARN("not init", K(ret)); } else if (!cell.is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(cell)); } else if (OB_FAIL(kv_proxy_->store_cell(cell, new_cell))) { LOG_WARN("store cell failed", K(ret)); } else { Cell *c = NULL; if (OB_FAIL(get_cell(cell.name_.ptr(), c))) { if (OB_ENTRY_NOT_EXIST != ret) { LOG_WARN("get cell failed", K(ret)); } else { // not found LOG_WARN("update cell not found in row, we ignore this and continue", K(cell), K_(row_id), "table_name", kv_proxy_->table_name_); if (OB_FAIL(extend_cell_array(cell_cnt_ + 1))) { LOG_WARN("extend cell array failed", K(ret), K_(cell_cnt)); } else { c = std::lower_bound(cells_, cells_ + cell_cnt_, new_cell); for (Cell *p = cells_ + cell_cnt_; p > c; --p) { *p = *(p - 1); } ++cell_cnt_; } } } if (OB_SUCC(ret)) { *c = new_cell; } } return ret; } DEF_TO_STRING(ObCoreTableProxy::Row) { int64_t pos = 0; J_OBJ_START(); BUF_PRINTF("\"row_id:%ld, \"cells\":", row_id_); J_ARRAY_START(); for (int64_t i = 0; i < cell_cnt_; ++i) { BUF_PRINTO(cells_[i]); J_COMMA(); } J_ARRAY_END(); J_OBJ_END(); return pos; } ObCoreTableProxy::ObCoreTableProxy( const char *table_name, ObISQLClient &sql_client, const uint64_t tenant_id) : table_name_(table_name), sql_client_(&sql_client), load_for_update_(false), cur_idx_(-1), all_row_(), allocator_(ObModIds::OB_CORE_TABLE_PROXY), tenant_id_(tenant_id) { } ObCoreTableProxy::~ObCoreTableProxy() { } int ObCoreTableProxy::load() { const bool for_update = false; int ret = OB_SUCCESS; if (!is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this)); } else if (OB_FAIL(load(for_update))) { LOG_WARN("load failed", K(ret), K(for_update)); } return ret; } int ObCoreTableProxy::load_for_update() { int ret = OB_SUCCESS; const bool for_update = true; if (!is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this)); } else if (OB_FAIL(load(for_update))) { LOG_WARN("load failed", K(ret), K(for_update)); } return ret; } int ObCoreTableProxy::load_gmt_create(const char *column_name, int64_t &gmt_create_value) { int ret = OB_SUCCESS; ObSqlString sql; SMART_VAR(ObMySQLProxy::MySQLResult, res) { ObMySQLResult *result = NULL; if (OB_ISNULL(column_name)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", KR(ret), K(column_name)); } else if (OB_FAIL(sql.assign_fmt("SELECT time_to_usec(gmt_create) FROM %s " "WHERE table_name = '%s' and column_name = '%s' ", OB_ALL_CORE_TABLE_TNAME, table_name_, column_name))) { LOG_WARN("assign sql failed", KR(ret), K(column_name), K(sql)); } else if (OB_FAIL(sql_client_->read(res, tenant_id_, sql.ptr()))) { LOG_WARN("execute sql failed", KR(ret), K_(tenant_id), K(sql)); } else if (OB_ISNULL(result = res.get_result())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to get result", K(ret), K(sql)); } else if (OB_FAIL(result->next())) { if (OB_ITER_END == ret) { LOG_WARN("query empty result, fail to load gmt_create column", KR(ret), K(table_name_), K(column_name), K(sql)); ret = OB_ENTRY_NOT_EXIST; } else { LOG_WARN("next_result failed", KR(ret), K(table_name_), K(column_name), K(sql)); } } else if (OB_FAIL(result->get_int(0L, gmt_create_value))) { LOG_WARN("get column fail", KR(ret), K(sql)); } } return ret; } int ObCoreTableProxy::load(const bool for_update) { all_row_.reset(); int ret = OB_SUCCESS; ObSqlString sql; SMART_VAR(ObMySQLProxy::MySQLResult, res) { ObMySQLResult *result = NULL; if (!is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this)); } else if (OB_FAIL(sql.assign_fmt("SELECT row_id, column_name, column_value " "FROM %s WHERE table_name = '%s' ORDER BY row_id, column_name%s", OB_ALL_CORE_TABLE_TNAME, table_name_, for_update ? " FOR UPDATE" : ""))) { LOG_WARN("assign sql failed", K(ret)); } else if (OB_FAIL(sql_client_->read(res, tenant_id_, sql.ptr()))) { LOG_WARN("execute sql failed", KR(ret), K_(tenant_id), K(sql)); } else if (NULL == (result = res.get_result())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to get result", K(ret), K(sql)); } else { int64_t row_id = OB_INVALID_INDEX; ObArray cells; while (OB_SUCCESS == ret && (OB_SUCC(result->next()))) { int64_t cur_row_id = OB_INVALID_INDEX; Cell cell; int64_t idx = 0; ret = GET_COL_IGNORE_NULL(result->get_int, idx++, cur_row_id); ret = GET_COL_IGNORE_NULL(result->get_varchar, idx++, cell.name_); ret = GET_COL_IGNORE_NULL(result->get_varchar, idx++, cell.value_); if (OB_FAIL(ret)) { } else { if (OB_INVALID_INDEX == cur_row_id || !cell.is_valid()) { ret = OB_INVALID_DATA; LOG_WARN("invalid row_id or name", K(ret), K(cur_row_id), K(cell)); } } if (OB_SUCC(ret)) { if (cur_row_id != row_id && OB_INVALID_INDEX != row_id) { if (OB_FAIL(add_row(row_id, cells))) { LOG_WARN("add row failed", K(ret), K(row_id), K(cells)); } else { cells.reuse(); } } } if (OB_SUCC(ret)) { row_id = cur_row_id; Cell stored_cell; if (OB_FAIL(store_cell(cell, stored_cell))) { LOG_WARN("store cell failed", K(ret), K(cell)); } else if (OB_FAIL(cells.push_back(stored_cell))) { LOG_WARN("add cell failed", K(ret)); } } } if (OB_SUCCESS != ret && OB_ITER_END != ret) { LOG_WARN("get result failed", K(ret), K(lbt())); } else { ret = OB_SUCCESS; if (OB_INVALID_INDEX != row_id) { if (OB_FAIL(add_row(row_id, cells))) { LOG_WARN("add row failed", K(ret), K(row_id), K(cells)); } } } } if (OB_SUCC(ret)) { if (OB_FAIL(seek_to_head())) { LOG_WARN("seek to head failed", K(ret)); } } if (OB_SUCC(ret)) { load_for_update_ = for_update; } } return ret; } int ObCoreTableProxy::seek_to_head() { int ret = OB_SUCCESS; if (!is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this)); } else { cur_idx_ = -1; } return ret; } int ObCoreTableProxy::add_row(const int64_t row_id, const ObIArray &cells) { int ret = OB_SUCCESS; Row row; if (!is_valid() || row_id < 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this), K(row_id)); } else if (OB_FAIL(row.init(row_id, *this, cells))) { LOG_WARN("init row failed", K(ret), K(row_id), K(cells)); } else if (OB_FAIL(all_row_.push_back(row))) { LOG_WARN("add row failed", K(ret)); } return ret; } int ObCoreTableProxy::next() { int ret = OB_SUCCESS; if (!is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this)); } else if (cur_idx_ < -1 || cur_idx_ >= all_row_.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid current index", K(ret), K_(cur_idx)); } else { if (cur_idx_ + 1 >= all_row_.count()) { ret = OB_ITER_END; } else { ++cur_idx_; } } return ret; } int ObCoreTableProxy::get_cur_row(const Row *&row) const { int ret = OB_SUCCESS; if (!is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this)); } else if (cur_idx_ < 0 || cur_idx_ >= all_row_.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid current index, may be next() not invoked", K(ret), K_(cur_idx)); } else { row = &all_row_.at(cur_idx_); } return ret; } int ObCoreTableProxy::get_int(const char *name, int64_t &value) const { int ret = OB_SUCCESS; const Row *row = NULL; if (!is_valid() || NULL == name) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this), K(name)); } else if (OB_FAIL(get_cur_row(row))) { LOG_WARN("get current row failed", K(ret)); } else if (NULL == row) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL row", K(ret)); } else if (OB_FAIL(row->get_int(name, value))) { if (OB_ERR_NULL_VALUE != ret) { LOG_WARN("get int value failed", K(ret), K(name), "row", *row); } } return ret; } int ObCoreTableProxy::get_uint(const char *name, uint64_t &value) const { int ret = OB_SUCCESS; const Row *row = NULL; if (!is_valid() || NULL == name) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this), K(name)); } else if (OB_FAIL(get_cur_row(row))) { LOG_WARN("get current row failed", K(ret)); } else if (NULL == row) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL row", K(ret)); } else if (OB_FAIL(row->get_uint(name, value))) { if (OB_ERR_NULL_VALUE != ret) { LOG_WARN("get int value failed", K(ret), K(name), "row", *row); } } return ret; } int ObCoreTableProxy::get_varchar(const char *name, common::ObString &value) const { int ret = OB_SUCCESS; const Row *row = NULL; if (!is_valid() || NULL == name) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this), K(name)); } else if (OB_FAIL(get_cur_row(row))) { LOG_WARN("get current row failed", K(ret)); } else if (NULL == row) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL row", K(ret)); } else if (OB_FAIL(row->get_varchar(name, value))) { if (OB_ERR_NULL_VALUE != ret) { LOG_WARN("get varchar value failed", K(ret), K(name), "row", *row); } } return ret; } int ObCoreTableProxy::get_timestamp(const char *name, const common::ObTimeZoneInfo *tz_info, int64_t &value) const { int ret = OB_SUCCESS; const Row *row = NULL; if (!is_valid() || NULL == name) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this), K(name)); } else if (OB_FAIL(get_cur_row(row))) { LOG_WARN("get current row failed", K(ret)); } else if (NULL == row) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL row", K(ret)); } else if (OB_FAIL(row->get_timestamp(name, tz_info, value))) { if (OB_ERR_NULL_VALUE != ret) { LOG_WARN("get timestamp value failed", K(ret), K(name), "row", *row); } } return ret; } //if the row not exist, execute insert; //otherwise update the row while the new is large than the old value of the row. int ObCoreTableProxy::incremental_update(const ObIArray &cells, const bool insert, int64_t &affected_rows) { int ret = OB_SUCCESS; if (!is_valid() || cells.count() <= 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this), "cell count", cells.count()); } else if (!load_for_update_) { ret = OB_ERR_SYS; LOG_WARN("table not loaded for update", K(ret)); } else { affected_rows = 0; int64_t match_rows = 0; FOREACH_X(row, all_row_, OB_SUCCESS == ret) { bool match = false; if (OB_FAIL(check_row_match(*row, cells, match))) { LOG_WARN("check row match failed", K(ret), "row", *row, K(cells)); } else { if (match) { match_rows++; if (OB_FAIL(execute_incremental_update_sql(*row, cells, affected_rows))) { LOG_WARN("execute update sql failed", K(ret)); } else if (OB_FAIL(update_row_struct(cells, *row))) { LOG_WARN("update row failed", K(ret), "row", *row); } } } } if (OB_SUCC(ret)) { if (0 == match_rows && insert) { Row insert_row; int64_t new_row_id = 0; if (OB_FAIL(generate_row_id(new_row_id))) { LOG_WARN("generate row id failed", K(ret)); } else { ObArray empty_cells; if (OB_FAIL(insert_row.init(new_row_id, *this, empty_cells))) { LOG_WARN("init row failed", K(ret), K(new_row_id)); } } ObArray new_cells; if (OB_FAIL(ret)) { } else if (OB_FAIL(execute_update_sql(insert_row, cells, affected_rows))) { LOG_WARN("execute update sql failed", K(ret)); } else { FOREACH_CNT_X(c, cells, OB_SUCCESS == ret) { if (OB_FAIL(new_cells.push_back(c->cell_))) { LOG_WARN("add cell failed", K(ret)); } } } if (OB_SUCC(ret)) { std::sort(new_cells.begin(), new_cells.end()); if (OB_FAIL(add_row(new_row_id, new_cells))) { LOG_WARN("add row failed", K(ret)); } } } } } return ret; } int ObCoreTableProxy::update(const ObIArray &cells, const bool insert, int64_t &affected_rows) { int ret = OB_SUCCESS; if (!is_valid() || cells.count() <= 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this), "cell count", cells.count()); } else if (!load_for_update_) { ret = OB_ERR_SYS; LOG_WARN("table not loaded for update", K(ret)); } else { affected_rows = 0; int64_t match_rows = 0; FOREACH_X(row, all_row_, OB_SUCCESS == ret) { bool match = false; if (OB_FAIL(check_row_match(*row, cells, match))) { LOG_WARN("check row match failed", K(ret), "row", *row, K(cells)); } else { if (match) { match_rows++; if (OB_FAIL(execute_update_sql(*row, cells, affected_rows))) { LOG_WARN("execute update sql failed", K(ret)); } else if (OB_FAIL(update_row_struct(cells, *row))) { LOG_WARN("update row failed", K(ret), "row", *row); } } } } if (OB_SUCC(ret)) { if (0 == match_rows && insert) { Row insert_row; int64_t new_row_id = 0; if (OB_FAIL(generate_row_id(new_row_id))) { LOG_WARN("generate row id failed", K(ret)); } else { ObArray empty_cells; if (OB_FAIL(insert_row.init(new_row_id, *this, empty_cells))) { LOG_WARN("init row failed", K(ret), K(new_row_id)); } } ObArray new_cells; if (OB_FAIL(ret)) { } else if (OB_FAIL(execute_update_sql(insert_row, cells, affected_rows))) { LOG_WARN("execute update sql failed", K(ret)); } else { FOREACH_CNT_X(c, cells, OB_SUCCESS == ret) { if (OB_FAIL(new_cells.push_back(c->cell_))) { LOG_WARN("add cell failed", K(ret)); } } } if (OB_SUCC(ret)) { std::sort(new_cells.begin(), new_cells.end()); if (OB_FAIL(add_row(new_row_id, new_cells))) { LOG_WARN("add row failed", K(ret)); } } } } } return ret; } int ObCoreTableProxy::update_row(const ObIArray &cells, int64_t &affected_rows) { int ret = OB_SUCCESS; const bool insert = false; if (!is_valid() || cells.count() <= 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this), "cell count", cells.count()); } else if (OB_FAIL(update(cells, insert, affected_rows))) { LOG_WARN("update cells failed", K(ret), K(cells), K(insert)); } return ret; } int ObCoreTableProxy::replace_row(const ObIArray &cells, int64_t &affected_rows) { int ret = OB_SUCCESS; const bool insert = true; if (!is_valid() || cells.count() <= 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this), "cell count", cells.count()); } else if (OB_FAIL(update(cells, insert, affected_rows))) { LOG_WARN("update cells failed", K(ret), K(cells), K(insert)); } return ret; } int ObCoreTableProxy::incremental_update_row(const ObIArray &cells, int64_t &affected_rows) { int ret = OB_SUCCESS; const bool insert = false; if (!is_valid() || cells.count() <= 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this), "cell count", cells.count()); } else if (OB_FAIL(incremental_update(cells, insert, affected_rows))) { LOG_WARN("update cells failed", K(ret), K(cells), K(insert)); } return ret; } int ObCoreTableProxy::incremental_replace_row(const ObIArray &cells, int64_t &affected_rows) { int ret = OB_SUCCESS; const bool insert = true; if (!is_valid() || cells.count() <= 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this), "cell count", cells.count()); } else if (OB_FAIL(incremental_update(cells, insert, affected_rows))) { LOG_WARN("update cells failed", K(ret), K(cells), K(insert)); } return ret; } int ObCoreTableProxy::delete_row(const ObIArray &cells, int64_t &affected_rows) { int ret = OB_SUCCESS; // cells may be empty (delete all row) if (!is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this)); } else if (!load_for_update_) { ret = OB_ERR_SYS; LOG_WARN("table not loaded for update", K(ret)); } else { affected_rows = 0; FOREACH_CNT_X(uc, cells, OB_SUCCESS == ret) { if (!uc->is_filter_cell_) { ret = OB_INVALID_ARGUMENT; LOG_WARN("cell not filter cell", K(ret), "cell", *uc); } } } for (int64_t i = 0; OB_SUCC(ret) && i < all_row_.count();) { bool match = false; if (OB_FAIL(check_row_match(all_row_.at(i), cells, match))) { LOG_WARN("check row match failed", K(ret), "row", all_row_.at(i), K(cells)); } else { if (!match) { i++; continue; } } if (OB_SUCC(ret)) { if (OB_FAIL(execute_delete_sql(all_row_.at(i).get_row_id()))) { LOG_WARN("delete row failed", K(ret), GETK(all_row_.at(i), row_id)); } else { affected_rows++; if (OB_FAIL(all_row_.remove(i))) { LOG_WARN("remove row failed", K(ret), K(i)); } else { if (cur_idx_ > i) { --cur_idx_; } } } } } return ret; } int ObCoreTableProxy::execute_delete_sql(const int64_t row_id) { int ret = OB_SUCCESS; if (!is_valid() || OB_INVALID_INDEX == row_id) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this), K(row_id)); } else { int64_t affected_rows = 0; ObSqlString sql; if (OB_FAIL(sql.assign_fmt("DELETE FROM %s WHERE table_name = '%s' AND row_id = %ld", OB_ALL_CORE_TABLE_TNAME, table_name_, row_id))) { LOG_WARN("assign sql failed", K(ret)); } else if (OB_FAIL(sql_client_->write(tenant_id_, sql.ptr(), affected_rows))) { LOG_WARN("execute sql failed", KR(ret), K_(tenant_id), K(sql)); } else { LOG_TRACE("execute sql", KR(ret), K_(tenant_id), K(sql)); } } return ret; } int ObCoreTableProxy::store_string(const common::ObString &src, common::ObString &dest) { int ret = OB_SUCCESS; if (!is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this)); } else { if (NULL == src.ptr()) { // null value dest = src; } else { char *buf = static_cast(allocator_.alloc(src.length() + 1)); if (NULL == buf) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("all memory for store string failed", K(ret), "length", src.length() + 1); } else { MEMCPY(buf, src.ptr(), src.length()); buf[src.length()] = '\0'; dest = ObString(0, src.length(), buf); } } } return ret; } int ObCoreTableProxy::store_cell(const Cell &src, Cell &dest) { int ret = OB_SUCCESS; if (!is_valid() || !src.is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this), K(src)); } else if (OB_FAIL(store_string(src.name_, dest.name_))) { LOG_WARN("store cell name failed", K(ret), K(src)); } else if (OB_FAIL(store_string(src.value_, dest.value_))) { LOG_WARN("store cell value failed", K(ret), K(src)); } else { dest.is_hex_value_ = src.is_hex_value_; } return ret; } int ObCoreTableProxy::check_row_match( const Row &row, const ObIArray &cells, bool &match) { int ret = OB_SUCCESS; match = true; if (!row.is_inited()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(row)); } FOREACH_CNT_X(uc, cells, OB_SUCCESS == ret && match) { // row match, if no filter cell exist. if (!uc->is_filter_cell_) { continue; } Cell *c = NULL; if (OB_FAIL(row.get_cell(uc->cell_.name_, c))) { if (OB_ENTRY_NOT_EXIST == ret) { ret = OB_SUCCESS; match = false; } else { LOG_WARN("get cell failed", K(ret), K(row), "name", uc->cell_.name_); } } else if (NULL == c) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL cell", K(ret)); } else { if (c->value_ != uc->cell_.value_) { match = false; } } } return ret; } int ObCoreTableProxy::execute_incremental_update_sql(const Row &row, const ObIArray &cells, int64_t &affected_rows) { int ret = OB_SUCCESS; int64_t affected_rows_bak = affected_rows; if (!is_valid() || !row.is_inited() || cells.count() <= 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this), K(row), K(cells)); } else { ObSqlString insert_sql; ObSqlString update_sql; FOREACH_CNT_X(uc, cells, OB_SUCCESS == ret) { Cell *c = NULL; bool is_insert = false; if (OB_FAIL(row.get_cell(uc->cell_.name_, c))) { if (OB_ENTRY_NOT_EXIST != ret) { LOG_WARN("get cell failed", K(ret), K(row), "name", uc->cell_.name_); } else { ret = OB_SUCCESS; is_insert = true; } } else if (NULL == c) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL cell", K(ret)); } else { int64_t old_value = atoll(c->value_.ptr()); int64_t new_value = atoll(uc->cell_.value_.ptr()); if (old_value >= new_value && OB_INVALID_SCHEMA_VERSION != new_value) { LOG_INFO("value is less than, just continue", KPC(c), KPC(uc), K(old_value), K(new_value)); continue; } } ObSqlString &value_sql = is_insert ? insert_sql : update_sql; if (OB_FAIL(ret)) { //skip } else if (NULL == uc->cell_.value_.ptr()) { if (OB_FAIL(value_sql.append_fmt("%s ('%s', %ld, '%.*s', NULL)", value_sql.empty() ? "" : ",", table_name_, row.get_row_id(), uc->cell_.name_.length(), uc->cell_.name_.ptr()))) { LOG_WARN("fail to append fmt", K(ret)); } } else { if (OB_FAIL(value_sql.append_fmt("%s ('%s', %ld, '%.*s', ", value_sql.empty() ? "" : ",", table_name_, row.get_row_id(), uc->cell_.name_.length(), uc->cell_.name_.ptr()))) { LOG_WARN("fail to append fmt", K(ret)); } else if (OB_FAIL(value_sql.append_fmt(uc->cell_.is_hex_value_ ? "%.*s)" : "'%.*s')", uc->cell_.value_.length(), uc->cell_.value_.ptr()))) { LOG_WARN("fail to append fmt", K(ret)); } } } DEBUG_SYNC(BEFORE_UPDATE_CORE_TABLE); int64_t affected = 0; ObSqlString sql; //batch insert //can use insert ... on duplicate update //the empty of __all_core_table and __all_root_table take into count, //in the case of concurrent reporting, the row_id is 0, if it use batch update, //the information will be overlapped. //batch_execute deem update_replica complete with not retry. if (OB_FAIL(ret)) { //skip } else if (insert_sql.empty()) { //skip } else if (OB_FAIL(sql.assign_fmt("INSERT INTO %s (table_name, row_id, column_name, column_value) VALUES %s ", OB_ALL_CORE_TABLE_TNAME, insert_sql.ptr()))) { LOG_WARN("fail to assign fmt", K(ret)); } else if (OB_FAIL(sql_client_->write(tenant_id_, sql.ptr(), affected))) { LOG_WARN("execute sql failed", KR(ret), K_(tenant_id), K(sql)); } else { LOG_TRACE("execute sql", KR(ret), K_(tenant_id), K(sql), K(affected)); } //batch update if (OB_FAIL(ret)) { //skip } else if (update_sql.empty()) { //skip } else if (OB_FAIL(sql.assign_fmt("INSERT INTO %s (table_name, row_id, column_name, column_value) VALUES %s " "ON DUPLICATE KEY UPDATE column_value = if ((cast(column_value as signed) > values(column_value)) " "and (values(column_value) != %ld), " "column_value, values(column_value))", OB_ALL_CORE_TABLE_TNAME, update_sql.ptr(), OB_INVALID_SCHEMA_VERSION))) { LOG_WARN("fail to assign fmt", K(ret)); } else if (OB_FAIL(sql_client_->write(tenant_id_, sql.ptr(), affected))) { LOG_WARN("execute sql failed", KR(ret), K_(tenant_id), K(sql)); } else { LOG_TRACE("execute sql", KR(ret), K_(tenant_id), K(sql), K(affected)); if (is_zero_row(affected)) { LOG_WARN("core table update do nothing", K(sql)); } } if (OB_SUCC(ret)) { if (!insert_sql.empty() || !update_sql.empty()) { affected_rows = affected_rows_bak + 1; } } } return ret; } int ObCoreTableProxy::execute_update_sql(const Row &row, const ObIArray &cells, int64_t &affected_rows) { int ret = OB_SUCCESS; int64_t affected_rows_bak = affected_rows; if (!is_valid() || !row.is_inited() || cells.count() <= 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this), K(row), K(cells)); } else { ObSqlString insert_sql; ObSqlString update_sql; FOREACH_CNT_X(uc, cells, OB_SUCCESS == ret) { Cell *c = NULL; bool is_insert = false; if (OB_FAIL(row.get_cell(uc->cell_.name_, c))) { if (OB_ENTRY_NOT_EXIST != ret) { LOG_WARN("get cell failed", K(ret), K(row), "name", uc->cell_.name_); } else { ret = OB_SUCCESS; is_insert = true; } } else if (NULL == c) { ret = OB_ERR_UNEXPECTED; LOG_WARN("NULL cell", K(ret)); } else if ((OB_ISNULL(c->value_.ptr()) && OB_NOT_NULL(uc->cell_.value_.ptr())) || (OB_NOT_NULL(c->value_.ptr()) && OB_ISNULL(uc->cell_.value_.ptr()))) { // NULL == ObString.ptr() means NULL, which is different with empty string(data_length is 0, but ptr is not null) } else if (c->value_ == uc->cell_.value_) { LOG_INFO("value is same, just continue", KPC(c), KPC(uc)); continue; } ObSqlString &value_sql = is_insert ? insert_sql : update_sql; if (OB_FAIL(ret)) { //skip } else if (NULL == uc->cell_.value_.ptr()) { if (OB_FAIL(value_sql.append_fmt("%s ('%s', %ld, '%.*s', NULL)", value_sql.empty() ? "" : ",", table_name_, row.get_row_id(), uc->cell_.name_.length(), uc->cell_.name_.ptr()))) { LOG_WARN("fail to append fmt", K(ret)); } } else { if (OB_FAIL(value_sql.append_fmt("%s ('%s', %ld, '%.*s', ", value_sql.empty() ? "" : ",", table_name_, row.get_row_id(), uc->cell_.name_.length(), uc->cell_.name_.ptr()))) { LOG_WARN("fail to append fmt", K(ret)); } else if (OB_FAIL(value_sql.append_fmt(uc->cell_.is_hex_value_ ? "%.*s)" : "'%.*s')", uc->cell_.value_.length(), uc->cell_.value_.ptr()))) { LOG_WARN("fail to append fmt", K(ret)); } } } int64_t affected = 0; ObSqlString sql; //batch insert //can use insert ... on duplicate update //the empty of __all_core_table and __all_root_table take into count, //in the case of concurrent reporting, the row_id is 0, if it use batch update, //the information will be overlapped. //batch_execute deem update_replica complete with not retry. if (OB_FAIL(ret)) { //skip } else if (insert_sql.empty()) { //skip } else if (OB_FAIL(sql.assign_fmt("INSERT INTO %s (table_name, row_id, column_name, column_value) VALUES %s ", OB_ALL_CORE_TABLE_TNAME, insert_sql.ptr()))) { LOG_WARN("fail to assign fmt", K(ret)); } else if (OB_FAIL(sql_client_->write(tenant_id_, sql.ptr(), affected))) { LOG_WARN("execute sql failed", KR(ret), K_(tenant_id), K(sql)); } else { LOG_TRACE("execute sql", KR(ret), K_(tenant_id), K(sql), K(affected)); } //batch update if (OB_FAIL(ret)) { //skip } else if (update_sql.empty()) { //skip } else if (OB_FAIL(sql.assign_fmt("INSERT INTO %s (table_name, row_id, column_name, column_value) VALUES %s " "ON DUPLICATE KEY UPDATE column_value = values(column_value)", OB_ALL_CORE_TABLE_TNAME, update_sql.ptr()))) { LOG_WARN("fail to assign fmt", K(ret)); } else if (OB_FAIL(sql_client_->write(tenant_id_, sql.ptr(), affected))) { LOG_WARN("execute sql failed", KR(ret), K_(tenant_id), K(sql)); } else { LOG_TRACE("execute sql", KR(ret), K_(tenant_id), K(sql), K(affected)); } if (OB_SUCC(ret)) { if (!insert_sql.empty() || !update_sql.empty()) { affected_rows = affected_rows_bak + 1; } } } return ret; } int ObCoreTableProxy::update_row_struct(const common::ObIArray &cells, Row &row) { int ret = OB_SUCCESS; if (!is_valid() || cells.count() <= 0 || !row.is_inited()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), K(cells), K(row), "cell count", cells.count()); } FOREACH_CNT_X(uc, cells, OB_SUCCESS == ret) { if (OB_FAIL(row.update_cell(uc->cell_))) { LOG_WARN("update cell failed", K(ret), "update_cell", *uc); } } return ret; } int ObCoreTableProxy::generate_row_id(int64_t &row_id) const { int ret = OB_SUCCESS; if (!is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this)); } else { int64_t max_row_id = 0; FOREACH(r, all_row_) { if (max_row_id < r->get_row_id()) { max_row_id = r->get_row_id(); } } row_id = max_row_id + 1; } return ret; } int ObCoreTableProxy::supplement_cell(const UpdateCell &cell) { int ret = OB_SUCCESS; if (!is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KPC(this)); } else if (!load_for_update_) { ret = OB_ERR_SYS; LOG_WARN("table not loaded for update", K(ret)); } else { int64_t affected_rows = 0; ObArray cells; ret = cells.push_back(cell); FOREACH_X(row, all_row_, OB_SUCCESS == ret) { if (OB_FAIL(execute_update_sql(*row, cells, affected_rows))) { LOG_WARN("execute update sql failed", K(ret)); } else if (OB_FAIL(update_row_struct(cells, *row))) { LOG_WARN("update row failed", K(ret), "row", *row); } } if (OB_SUCC(ret)) { if (all_row_.count() != affected_rows) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected affected rows", K(ret), K(affected_rows), K(all_row_.count()), K(all_row_)); } } } return ret; } } // end namespace share } // end namespace oceanbase