Files
oceanbase/src/sql/optimizer/ob_log_link.cpp
2023-06-12 02:43:11 +00:00

251 lines
8.4 KiB
C++

/**
* 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 SQL_OPT
#include "sql/optimizer/ob_log_link.h"
#include "sql/ob_sql_utils.h"
using namespace oceanbase::sql;
using namespace oceanbase::common;
using namespace oceanbase::sql::log_op_def;
namespace oceanbase
{
namespace sql
{
ObLogLink::ObLogLink(ObLogPlan &plan)
: ObLogicalOperator(plan),
allocator_(plan.get_allocator()),
stmt_fmt_buf_(NULL),
stmt_fmt_len_(0),
is_reverse_link_(false),
tm_dblink_id_(OB_INVALID_ID),
param_infos_()
{}
int ObLogLink::compute_sharding_info()
{
int ret = OB_SUCCESS;
ObOptimizerContext *opt_ctx = NULL;
if (OB_ISNULL(get_plan()) ||
OB_ISNULL(opt_ctx = &get_plan()->get_optimizer_context())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else {
strong_sharding_ = opt_ctx->get_local_sharding();
}
return ret;
}
int ObLogLink::compute_op_parallel_and_server_info()
{
int ret = OB_SUCCESS;
server_list_.reuse();
if (OB_ISNULL(get_plan())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (OB_FAIL(server_list_.push_back(get_plan()->get_optimizer_context().get_local_server_addr()))) {
LOG_WARN("failed to assign das path server list", K(ret));
} else {
set_parallel(1);
set_server_cnt(1);
}
return ret;
}
int ObLogLink::est_cost()
{
int ret = OB_SUCCESS;
card_ = 0;
op_cost_ = 0;
cost_ = 0;
width_ = 0;
return ret;
}
int ObLogLink::print_link_stmt(char *buf, int64_t buf_len)
{
int ret = OB_SUCCESS;
if (stmt_fmt_len_ > buf_len) {
ret = OB_SIZE_OVERFLOW;
LOG_WARN("print link stmt failed", K(ret), K(stmt_fmt_len_), K(buf_len));
} else {
MEMCPY(buf, stmt_fmt_buf_, stmt_fmt_len_);
char *ch = buf;
char *stmt_end = buf + stmt_fmt_len_ - 3;
while (ch < stmt_end) {
if (0 == ch[0] && 0 == ch[1]) {
uint16_t param_idx = *(uint16_t *)(ch + 2);
ch[0] = '$';
if (param_idx > 999) {
ch[1] = 'M';
ch[2] = 'A';
ch[3] = 'X';
} else {
ch[3] = static_cast<char>('0' + param_idx % 10);
param_idx /= 10;
ch[2] = static_cast<char>('0' + param_idx % 10);
param_idx /= 10;
ch[1] = static_cast<char>('0' + param_idx % 10);
}
ch += 4;
} else {
ch++;
}
}
}
return ret;
}
int ObLogLink::get_plan_item_info(PlanText &plan_text,
ObSqlPlanItem &plan_item)
{
int ret = OB_SUCCESS;
if (OB_FAIL(ObLogicalOperator::get_plan_item_info(plan_text, plan_item))) {
LOG_WARN("failed to get plan item info", K(ret));
} else {
BEGIN_BUF_PRINT;
if (false && OB_FAIL(BUF_PRINTF(",dblink_id=%lu,", get_dblink_id()))) { // explain basic will print dlbink id, dblink id will change every time when case run
LOG_WARN("BUF_PRINTF failed", K(ret));
} else if (OB_FAIL(BUF_PRINTF("link_stmt="))) {
LOG_WARN("BUF_PRINTF failed", K(ret));
} else if (OB_FAIL(print_link_stmt(buf + pos, buf_len - pos))) {
LOG_WARN("failed to print link stmt", K(ret));
} else {
pos += stmt_fmt_len_;
}
END_BUF_PRINT(plan_item.special_predicates_,
plan_item.special_predicates_len_);
}
return ret;
}
// see comment in ObConstRawExpr::get_name_internal().
int ObLogLink::gen_link_stmt_param_infos()
{
int ret = OB_SUCCESS;
if (OB_ISNULL(stmt_fmt_buf_) || stmt_fmt_len_ <= 0) {
ret = OB_NOT_INIT;
LOG_WARN("stmt fmt is not inited", KP(stmt_fmt_buf_), K(stmt_fmt_len_));
} else {
param_infos_.reset();
}
int64_t param_pos = 0;
int64_t param_idx = 0;
const int64_t param_len = ObLinkStmtParam::get_param_len();
while (OB_SUCC(ret) && param_idx >= 0) {
int8_t type_value;
if (OB_FAIL(ObLinkStmtParam::read_next(stmt_fmt_buf_, stmt_fmt_len_, param_pos, param_idx, type_value))) {
LOG_WARN("failed to read next param", K(ret));
} else if (param_idx < 0) {
// skip.
} else if (OB_FAIL(param_infos_.push_back(ObParamPosIdx(static_cast<int32_t>(param_pos),
static_cast<int32_t>(param_idx),
type_value)))) {
LOG_WARN("failed to push back param pos idx", K(ret), K(param_pos), K(param_idx), K(type_value));
} else {
param_pos += param_len;
}
}
return ret;
}
int ObLogLink::mark_exec_params(ObDMLStmt *stmt)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret));
} else {
common::ObIArray<ObQueryRefRawExpr*> &subquery_exprs = stmt->get_subquery_exprs();
for (int64_t i = 0; OB_SUCC(ret) && i < subquery_exprs.count(); i ++) {
ObQueryRefRawExpr *expr = subquery_exprs.at(i);
if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret));
} else {
for (int64_t j = 0; OB_SUCC(ret) && j < expr->get_exec_params().count(); j ++) {
ObExecParamRawExpr *param_expr = NULL;
if (OB_ISNULL(param_expr = expr->get_exec_params().at(j))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null", K(ret));
} else {
param_expr->set_ref_same_dblink(true);
}
}
}
}
}
if (OB_SUCC(ret)) {
ObSEArray<ObSelectStmt *, 4> child_stmts;
if (OB_FAIL(stmt->get_child_stmts(child_stmts))) {
LOG_WARN("failed to get child stmts", K(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && i < child_stmts.count(); i ++) {
OZ(SMART_CALL(mark_exec_params(child_stmts.at(i))));
}
}
return ret;
}
int ObLogLink::set_link_stmt(const ObDMLStmt* stmt)
{
int ret = OB_SUCCESS;
const ObLogPlan *plan = get_plan();
if (NULL == stmt) {
stmt = get_stmt();
}
ObString sql;
ObObjPrintParams print_param;
print_param.for_dblink_ = 1;
// only link scan need print flashback query for dblink table
ObOptimizerContext *opt_ctx = NULL;
ObQueryCtx *query_ctx = NULL;
ObSQLSessionInfo *session = NULL;
int64_t session_query_timeout_us = 0;
int64_t hint_query_timeout_us = 0;
if (OB_ISNULL(stmt) || OB_ISNULL(plan) ||
OB_ISNULL(opt_ctx = &get_plan()->get_optimizer_context()) ||
OB_ISNULL(session = opt_ctx->get_session_info()) ||
OB_ISNULL(print_param.exec_ctx_ = opt_ctx->get_exec_ctx())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", KP(opt_ctx), KP(stmt), KP(session), KP(plan), K(ret));
} else if (NULL == (query_ctx = stmt->get_query_ctx())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (FALSE_IT(hint_query_timeout_us = query_ctx->get_query_hint_for_update().get_global_hint().query_timeout_)) {
} else if (OB_FAIL(session->get_query_timeout(session_query_timeout_us))) {
LOG_WARN("failed to get session query timeout", K(ret));
} else if (-1 == hint_query_timeout_us &&
FALSE_IT(query_ctx->get_query_hint_for_update().get_global_hint().merge_query_timeout_hint(session_query_timeout_us))) {
// do nothing
} else if (FALSE_IT(query_ctx->get_query_hint_for_update().get_global_hint().set_flashback_read_tx_uncommitted(true))) {
} else if (OB_FAIL(mark_exec_params(const_cast<ObDMLStmt*>(stmt)))) {
LOG_WARN("failed to mark exec params", K(ret));
} else if (OB_FAIL(ObSQLUtils::reconstruct_sql(plan->get_allocator(), stmt, sql, opt_ctx->get_schema_guard(), print_param))) {
LOG_WARN("failed to reconstruct link sql", KP(stmt), KP(plan), K(get_dblink_id()), K(ret));
} else {
stmt_fmt_buf_ = sql.ptr();
stmt_fmt_len_ = sql.length();
LOG_DEBUG("loglink succ to reconstruct link sql", K(sql));
}
if (-1 == hint_query_timeout_us) { // restore query_timeout_hint
query_ctx->get_query_hint_for_update().get_global_hint().reset_query_timeout_hint();
}
query_ctx->get_query_hint_for_update().get_global_hint().set_flashback_read_tx_uncommitted(false);
return ret;
}
} // namespace sql
} // namespace oceanbase