4464 lines
206 KiB
C++
4464 lines
206 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
|
|
#include "sql/ob_sql.h"
|
|
#include "lib/container/ob_array.h"
|
|
#include "lib/container/ob_se_array.h"
|
|
#include "lib/encrypt/ob_encrypted_helper.h"
|
|
#include "lib/json/ob_json.h"
|
|
#include "lib/profile/ob_profile_log.h"
|
|
#include "lib/profile/ob_trace_id.h"
|
|
#include "lib/thread_local/ob_tsi_factory.h"
|
|
#include "lib/string/ob_sql_string.h"
|
|
#include "lib/json/ob_json_print_utils.h"
|
|
#include "lib/profile/ob_perf_event.h"
|
|
#include "lib/rc/context.h"
|
|
#include "share/ob_truncated_string.h"
|
|
#include "share/partition_table/ob_partition_location.h"
|
|
#include "share/schema/ob_schema_getter_guard.h"
|
|
#include "share/ob_autoincrement_service.h"
|
|
#include "share/ob_rs_mgr.h"
|
|
#include "share/config/ob_server_config.h"
|
|
#include "common/sql_mode/ob_sql_mode_utils.h"
|
|
#include "sql/ob_sql_context.h"
|
|
#include "sql/ob_result_set.h"
|
|
#include "sql/optimizer/ob_log_plan_factory.h"
|
|
#include "sql/plan_cache/ob_plan_cache.h"
|
|
#include "sql/plan_cache/ob_pcv_set.h"
|
|
#include "sql/engine/table/ob_virtual_table_ctx.h"
|
|
#include "sql/ob_sql_init.h"
|
|
#include "sql/ob_sql_utils.h"
|
|
#include "sql/monitor/ob_security_audit_utils.h"
|
|
#include "sql/optimizer/ob_log_plan.h"
|
|
#include "sql/optimizer/ob_optimizer.h"
|
|
#include "sql/optimizer/ob_optimizer_context.h"
|
|
#include "sql/parser/ob_parser.h"
|
|
#include "sql/parser/parse_malloc.h"
|
|
#include "sql/parser/parse_node.h"
|
|
#include "sql/parser/parse_define.h"
|
|
#include "sql/resolver/cmd/ob_help_stmt.h"
|
|
#include "sql/resolver/ob_cmd.h"
|
|
#include "sql/resolver/ob_resolver.h"
|
|
#include "sql/resolver/ob_schema_checker.h"
|
|
#include "sql/resolver/cmd/ob_variable_set_stmt.h"
|
|
#include "sql/resolver/cmd/ob_call_procedure_stmt.h"
|
|
#include "sql/resolver/cmd/ob_anonymous_block_stmt.h"
|
|
#include "sql/resolver/ob_resolver_utils.h"
|
|
#include "sql/privilege_check/ob_privilege_check.h"
|
|
#include "share/system_variable/ob_system_variable_alias.h"
|
|
#include "sql/rewrite/ob_transformer_impl.h"
|
|
#include "sql/rewrite/ob_transform_project_pruning.h"
|
|
#include "sql/rewrite/ob_transform_pre_process.h"
|
|
#include "sql/plan_cache/ob_cache_object_factory.h"
|
|
#include "sql/monitor/ob_phy_plan_monitor_info.h"
|
|
#include "sql/plan_cache/ob_ps_sql_utils.h"
|
|
#include "lib/utility/ob_tracepoint.h"
|
|
#include "observer/ob_server_struct.h"
|
|
#include "observer/omt/ob_th_worker.h"
|
|
#include "sql/resolver/dml/ob_del_upd_stmt.h"
|
|
#include "sql/resolver/dml/ob_update_stmt.h"
|
|
#include "sql/resolver/expr/ob_raw_expr_printer.h"
|
|
#include "sql/engine/px/ob_px_admission.h"
|
|
#include "sql/code_generator/ob_code_generator.h"
|
|
#include "observer/omt/ob_tenant_config_mgr.h"
|
|
#include "sql/executor/ob_executor_rpc_impl.h"
|
|
#include "sql/executor/ob_remote_executor_processor.h"
|
|
#include "sql/udr/ob_udr_utils.h"
|
|
#include "sql/udr/ob_udr_mgr.h"
|
|
#include "sql/udr/ob_udr_analyzer.h"
|
|
#include "common/ob_smart_call.h"
|
|
|
|
namespace oceanbase
|
|
{
|
|
using namespace common;
|
|
using namespace rpc::frame;
|
|
using namespace obrpc;
|
|
using namespace share;
|
|
using namespace share::schema;
|
|
|
|
namespace sql
|
|
{
|
|
|
|
const int64_t ObSql::max_error_length = 80;
|
|
const int64_t ObSql::SQL_MEM_SIZE_LIMIT = 1024 * 1024 * 64;
|
|
|
|
int ObSql::init(common::ObOptStatManager *opt_stat_mgr,
|
|
ObReqTransport *transport,
|
|
common::ObITabletScan *vt_partition_service,
|
|
common::ObAddr &addr,
|
|
share::ObRsMgr &rs_mgr)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(opt_stat_mgr)
|
|
|| OB_ISNULL(transport)
|
|
|| OB_ISNULL(vt_partition_service)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid args",
|
|
K(ret),
|
|
KP(opt_stat_mgr),
|
|
KP(transport),
|
|
KP(vt_partition_service));
|
|
} else {
|
|
if (OB_FAIL(plan_cache_manager_.init(addr))) {
|
|
LOG_WARN("Failed to init plan cache manager", K(ret));
|
|
} else if (OB_FAIL(queue_.init(1, 1024))) {
|
|
LOG_WARN("queue init failed", K(ret));
|
|
} else {
|
|
opt_stat_mgr_ = opt_stat_mgr;
|
|
transport_ = transport;
|
|
vt_partition_service_ = vt_partition_service;
|
|
self_addr_ = addr;
|
|
rs_mgr_ = &rs_mgr;
|
|
inited_ = true;
|
|
queue_.start();
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void ObSql::destroy() {
|
|
if (inited_) {
|
|
plan_cache_manager_.destroy();
|
|
queue_.destroy();
|
|
inited_ = false;
|
|
}
|
|
}
|
|
|
|
void ObSql::stat()
|
|
{
|
|
sql::print_sql_stat();
|
|
}
|
|
|
|
int ObSql::stmt_prepare(const common::ObString &stmt,
|
|
ObSqlCtx &context,
|
|
ObResultSet &result,
|
|
bool is_inner_sql/*true*/)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
LinkExecCtxGuard link_guard(result.get_session(), result.get_exec_context());
|
|
if (OB_FAIL(sanity_check(context))) {
|
|
LOG_WARN("Failed to do sanity check", K(ret));
|
|
} else if (OB_FAIL(handle_ps_prepare(stmt, context, result, is_inner_sql))) {
|
|
LOG_WARN("failed to handle ps query", K(stmt), K(ret));
|
|
}
|
|
if (OB_FAIL(ret) && OB_SUCCESS == result.get_errcode()) {
|
|
result.set_errcode(ret);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::stmt_query(const common::ObString &stmt, ObSqlCtx &context, ObResultSet &result)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
LinkExecCtxGuard link_guard(result.get_session(), result.get_exec_context());
|
|
FLTSpanGuard(sql_compile);
|
|
ObTruncatedString trunc_stmt(stmt);
|
|
#if !defined(NDEBUG)
|
|
LOG_INFO("Begin to handle text statement", K(trunc_stmt),
|
|
"sess_id", result.get_session().get_sessid(),
|
|
"tenant_id", result.get_session().get_effective_tenant_id(),
|
|
"execution_id", result.get_session().get_current_execution_id());
|
|
#endif
|
|
//NG_TRACE_EXT(parse_begin, OB_ID(stmt), trunc_stmt.string(), OB_ID(stmt_len), stmt.length());
|
|
//1 check inited
|
|
if (OB_FAIL(sanity_check(context))) {
|
|
LOG_WARN("Failed to do sanity check", K(ret));
|
|
} else if (OB_FAIL(handle_text_query(stmt, context, result))) {
|
|
if (OB_EAGAIN != ret && OB_ERR_PROXY_REROUTE != ret) {
|
|
LOG_WARN("fail to handle text query", K(stmt), K(ret));
|
|
}
|
|
} else {
|
|
result.get_session().set_exec_min_cluster_version();
|
|
}
|
|
//LOG_DEBUG("result errno", N_ERR_CODE, result.get_errcode(), K(ret));
|
|
if (OB_SUCCESS != ret
|
|
&& OB_SUCCESS == result.get_errcode()) {
|
|
result.set_errcode(ret);
|
|
}
|
|
if (OB_ISNULL(result.get_physical_plan())) {
|
|
} else {
|
|
FLT_SET_TAG(plan_hash, result.get_physical_plan()->get_plan_hash_value());
|
|
}
|
|
FLT_SET_TAG(database_id, result.get_session().get_database_id(),
|
|
sql_id, context.sql_id_);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::stmt_execute(const ObPsStmtId stmt_id,
|
|
const stmt::StmtType stmt_type,
|
|
const ParamStore ¶ms,
|
|
ObSqlCtx &context,
|
|
ObResultSet &result,
|
|
bool is_inner_sql)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
LinkExecCtxGuard link_guard(result.get_session(), result.get_exec_context());
|
|
if (OB_FAIL(sanity_check(context))) {
|
|
LOG_WARN("failed to do sanity check", K(ret));
|
|
} else if (OB_FAIL(init_result_set(context, result))) {
|
|
LOG_WARN("failed to init result set", K(ret));
|
|
} else if (OB_FAIL(handle_ps_execute(stmt_id, stmt_type, params,
|
|
context, result, is_inner_sql))) {
|
|
if (OB_ERR_PROXY_REROUTE != ret) {
|
|
LOG_WARN("failed to handle ps execute", K(stmt_id), K(ret));
|
|
}
|
|
} else {
|
|
result.get_session().set_exec_min_cluster_version();
|
|
}
|
|
if (OB_FAIL(ret) && OB_SUCCESS == result.get_errcode()) {
|
|
result.set_errcode(ret);
|
|
}
|
|
FLT_SET_TAG(sql_id, context.sql_id_);
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::stmt_list_field(const common::ObString &table_name,
|
|
const common::ObString &wild_str,
|
|
ObSqlCtx &context,
|
|
ObResultSet &result)
|
|
{
|
|
UNUSED(table_name);
|
|
UNUSED(wild_str);
|
|
UNUSED(context);
|
|
UNUSED(result);
|
|
return OB_NOT_IMPLEMENT;
|
|
}
|
|
|
|
int ObSql::fill_result_set(ObResultSet &result_set, ObSqlCtx *context, const bool is_ps_mode, ObStmt &basic_stmt)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
ObStmt *stmt = &basic_stmt;
|
|
ObExecContext &ectx = result_set.get_exec_context();
|
|
ObPhysicalPlanCtx *pctx = ectx.get_physical_plan_ctx();
|
|
if (OB_UNLIKELY(NULL == context) || OB_UNLIKELY(NULL == context->session_info_) || OB_UNLIKELY(NULL == pctx)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(ret), K(context), K(pctx),
|
|
"session", (context != NULL) ? context->session_info_ : NULL);
|
|
} else {
|
|
result_set.set_affected_rows(0);
|
|
result_set.set_warning_count(0);
|
|
result_set.set_message("");
|
|
ObString type_name = ObString::make_string("varchar");
|
|
number::ObNumber number;
|
|
number.set_zero();
|
|
ObDelUpdStmt *del_upd_stmt = NULL;
|
|
ObField field;
|
|
common::ObIAllocator &alloc = result_set.get_mem_pool();
|
|
ObCharsetType result_charset = CHARSET_INVALID;
|
|
ObCollationType collation_type = CS_TYPE_INVALID;
|
|
context->session_info_->get_character_set_results(result_charset);
|
|
collation_type =
|
|
ObCharset::get_default_collation_by_mode(result_charset, lib::is_oracle_mode());
|
|
switch (stmt->get_stmt_type()) {
|
|
case stmt::T_SELECT: {
|
|
if (OB_FAIL(fill_select_result_set(result_set, context, is_ps_mode, collation_type, type_name,
|
|
basic_stmt, field))) {
|
|
LOG_WARN("fill select result set failed", K(ret));
|
|
}
|
|
break;
|
|
}
|
|
case stmt::T_INSERT:
|
|
case stmt::T_REPLACE:
|
|
case stmt::T_UPDATE:
|
|
case stmt::T_DELETE: {
|
|
del_upd_stmt = static_cast<ObDelUpdStmt *>(stmt);
|
|
if (!del_upd_stmt->is_returning()) {
|
|
break;
|
|
}
|
|
const common::ObIArray<ObRawExpr*> *returning_exprs = &(del_upd_stmt->get_returning_exprs());
|
|
const common::ObIArray<ObString> &returning_strs = del_upd_stmt->get_returning_strs();
|
|
int64_t size = returning_exprs->count();
|
|
field.charsetnr_ = CS_TYPE_UTF8MB4_GENERAL_CI;
|
|
if (OB_FAIL(result_set.reserve_field_columns(size))) {
|
|
LOG_WARN("reserve field columns failed", K(ret), K(size));
|
|
}
|
|
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < size; i++) {
|
|
ObRawExpr *expr = returning_exprs->at(i);
|
|
if (OB_UNLIKELY(OB_ISNULL(expr))) {
|
|
ret = OB_ERR_ILLEGAL_ID;
|
|
LOG_WARN("fail to get expr", K(ret), K(i), K(size));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
ObCollationType charsetnr;
|
|
if (OB_FAIL(ObCharset::get_default_collation(expr->get_collation_type(), charsetnr))) {
|
|
LOG_WARN("fail to get table item charset collation", K(expr->get_collation_type()), K(i), K(ret));
|
|
} else {
|
|
field.charsetnr_ = static_cast<uint16_t>(charsetnr);
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
expr->deduce_type(context->session_info_);
|
|
field.type_.set_type(expr->get_data_type());
|
|
field.accuracy_ = expr->get_accuracy();
|
|
field.flags_ = static_cast<uint16_t>(expr->get_result_flag());
|
|
// Setup Collation and Collation levl
|
|
if (ob_is_string_or_lob_type(static_cast<ObObjType>(expr->get_data_type()))
|
|
|| ob_is_raw(static_cast<ObObjType>(expr->get_data_type()))
|
|
|| ob_is_enum_or_set_type(static_cast<ObObjType>(expr->get_data_type()))) {
|
|
field.type_.set_collation_type(expr->get_collation_type());
|
|
field.type_.set_collation_level(expr->get_collation_level());
|
|
}
|
|
if (ObVarcharType == field.type_.get_type()) {
|
|
field.type_.set_varchar(type_name);
|
|
} else if (ObNumberType == field.type_.get_type()) {
|
|
field.type_.set_number(number);
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(ob_write_string(alloc, returning_strs.at(i), field.cname_))) {
|
|
LOG_WARN("fail to alloc", K(ret), K(returning_strs.at(i)));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
field.is_paramed_select_item_ = false;
|
|
field.paramed_ctx_ = NULL;
|
|
if (OB_FAIL(result_set.add_field_column(field))) {
|
|
LOG_WARN("fail to add field column to result_set", K(ret));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
field.cname_.assign(NULL, 0);
|
|
field.org_cname_.assign(NULL, 0);
|
|
field.dname_.assign(NULL, 0);
|
|
field.tname_.assign(NULL, 0);
|
|
field.org_tname_.assign(NULL, 0);
|
|
field.type_.reset();
|
|
field.type_.set_type(ObExtendType);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case stmt::T_EXPLAIN: {
|
|
ObString tname = ObString::make_string("explain_table");
|
|
ObString cname = ObString::make_string("Query Plan");
|
|
field.tname_ = tname;
|
|
field.org_tname_ = tname;
|
|
field.cname_ = cname;
|
|
field.org_cname_ = cname;
|
|
field.type_.set_type(ObVarcharType);
|
|
field.charsetnr_ = CS_TYPE_UTF8MB4_GENERAL_CI;
|
|
field.type_.set_collation_type(CS_TYPE_UTF8MB4_GENERAL_CI);
|
|
field.type_.set_collation_level(CS_LEVEL_IMPLICIT);
|
|
field.type_.set_varchar(type_name);
|
|
if (OB_FAIL(result_set.reserve_field_columns(1))) {
|
|
LOG_WARN("reserve field columns failed", K(ret));
|
|
} else if (OB_FAIL(result_set.add_field_column(field))) {
|
|
LOG_WARN("fail to add field column to result_set", K(ret));
|
|
}
|
|
break;
|
|
}
|
|
case stmt::T_HELP: {
|
|
ObHelpStmt *help_stmt = static_cast<ObHelpStmt *>(stmt);
|
|
if (OB_UNLIKELY(NULL == help_stmt)) {
|
|
ret = OB_ERR_PARSE_SQL;
|
|
LOG_WARN("logical plan of help statement error", K(ret));
|
|
} else {
|
|
ObString tname = ObString::make_string("help_table");
|
|
field.tname_ = tname;
|
|
field.org_tname_ = tname;
|
|
field.charsetnr_ = CS_TYPE_UTF8MB4_GENERAL_CI;
|
|
int64_t col_count = help_stmt->get_col_count();
|
|
if (OB_FAIL(result_set.reserve_field_columns(col_count))) {
|
|
LOG_WARN("reserve field columns failed", K(ret), K(col_count));
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < col_count; ++i) {
|
|
field.type_.set_type(ObVarcharType);
|
|
field.type_.set_collation_type(CS_TYPE_UTF8MB4_GENERAL_CI);
|
|
field.type_.set_collation_level(CS_LEVEL_IMPLICIT);
|
|
field.type_.set_varchar(type_name);
|
|
ObString col_name;
|
|
if (OB_FAIL(help_stmt->get_col_name(i, col_name))) {
|
|
LOG_WARN("fail to get column name", K(ret), K(i));
|
|
} else if (OB_FAIL(ob_write_string(alloc, col_name, field.cname_))) {
|
|
LOG_WARN("fail to alloc string", K(ret), "name", col_name);
|
|
} else if (OB_FAIL(ob_write_string(alloc, col_name, field.org_cname_))) {
|
|
LOG_WARN("fail to alloc string", K(ret), "name", col_name);
|
|
} else if (OB_FAIL(result_set.add_field_column(field))) {
|
|
LOG_WARN("fail to add field column to result_set", K(ret));
|
|
} else {
|
|
field.cname_.assign(NULL, 0);
|
|
field.org_cname_.assign(NULL, 0);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case stmt::T_CALL_PROCEDURE: {
|
|
ObCallProcedureStmt &call_stmt = static_cast<ObCallProcedureStmt&>(basic_stmt);
|
|
ObString tname = ObString::make_string("procedure");
|
|
|
|
int64_t size = call_stmt.get_output_count();
|
|
field.charsetnr_ = CS_TYPE_UTF8MB4_GENERAL_CI;
|
|
|
|
if (0 == call_stmt.get_output_count()) {
|
|
break;
|
|
}
|
|
|
|
if (OB_SUCC(ret) && OB_FAIL(result_set.reserve_field_columns(size))) {
|
|
LOG_WARN("reserve field columns failed", K(ret), K(size));
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < size; ++i) {
|
|
ObCollationType charsetnr;
|
|
ObDataType *type = call_stmt.get_out_type().at(i).get_data_type();
|
|
ObObjType out_obj_type = call_stmt.get_out_type().at(i).get_obj_type();
|
|
if (ObUnknownType == out_obj_type
|
|
|| ObExtendType == out_obj_type) {
|
|
// do nothing ...
|
|
} else if (OB_NOT_NULL(type)) {
|
|
if (ob_is_string_or_lob_type(out_obj_type)
|
|
&& CS_TYPE_ANY == type->get_collation_type()) {
|
|
charsetnr = ObCharset::is_valid_collation(collation_type)
|
|
? collation_type
|
|
: CS_TYPE_UTF8MB4_BIN;
|
|
} else {
|
|
OZ (ObCharset::get_default_collation(type->get_collation_type(), charsetnr));
|
|
}
|
|
OX (field.charsetnr_ = static_cast<uint16_t>(charsetnr));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
field.type_.set_type(out_obj_type);
|
|
if (OB_NOT_NULL(type)) {
|
|
field.accuracy_ = type->get_accuracy();
|
|
// Setup Collation and Collation levl
|
|
if (ob_is_string_or_lob_type(out_obj_type)
|
|
|| ob_is_raw(out_obj_type)
|
|
|| ob_is_enum_or_set_type(out_obj_type)) {
|
|
field.type_.set_collation_type(type->get_collation_type());
|
|
field.type_.set_collation_level(type->get_collation_level());
|
|
}
|
|
}
|
|
if (ObExtendType == out_obj_type) {
|
|
field.length_ = field.accuracy_.get_length();
|
|
} else if (ObCharType == out_obj_type
|
|
|| ObVarcharType == out_obj_type
|
|
|| ob_is_nstring_type(out_obj_type)) {
|
|
if (-1 == field.accuracy_.get_length()) {
|
|
field.length_ = ObCharType == out_obj_type ?
|
|
OB_MAX_ORACLE_CHAR_LENGTH_BYTE : OB_MAX_ORACLE_VARCHAR_LENGTH;
|
|
} else {
|
|
field.length_ = field.accuracy_.get_length();
|
|
}
|
|
} else if (ob_is_enum_or_set_type(out_obj_type)) {
|
|
CK (OB_NOT_NULL(type));
|
|
OZ (common::ObField::get_field_mb_length(field.type_.get_type(),
|
|
field.accuracy_,
|
|
type->get_collation_type(),
|
|
field.length_));
|
|
OX (field.type_.set_type(ObVarcharType));
|
|
} else {
|
|
OZ (common::ObField::get_field_mb_length(field.type_.get_type(),
|
|
field.accuracy_,
|
|
common::CS_TYPE_INVALID,
|
|
field.length_));
|
|
}
|
|
// Setup Scale
|
|
if (OB_SUCC(ret)) {
|
|
if (ObVarcharType == field.type_.get_type()) {
|
|
field.type_.set_varchar(type_name);
|
|
} else if (ObNumberType == field.type_.get_type()) {
|
|
field.type_.set_number(number);
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(ob_write_string(alloc, tname, field.tname_))) {
|
|
LOG_WARN("fail to alloc string", K(call_stmt.get_out_name().at(i)), K(ret));
|
|
} else if (OB_FAIL(ob_write_string(alloc, tname, field.org_tname_))) {
|
|
LOG_WARN("fail to alloc string", K(call_stmt.get_out_name().at(i)), K(ret));
|
|
} else if (OB_FAIL(ob_write_string(alloc, call_stmt.get_out_name().at(i), field.cname_))) {
|
|
LOG_WARN("fail to alloc string", K(call_stmt.get_out_name().at(i)), K(ret));
|
|
} else if (OB_FAIL(ob_write_string(alloc, call_stmt.get_out_name().at(i), field.org_cname_))) {
|
|
LOG_WARN("fail to alloc string", K(call_stmt.get_out_name().at(i)), K(ret));
|
|
} else if (OB_FAIL(ob_write_string(alloc, call_stmt.get_out_type_name().at(i), field.type_name_))) {
|
|
LOG_WARN("fail to alloc string", K(call_stmt.get_out_type_name().at(i)), K(ret));
|
|
} else if (OB_FAIL(ob_write_string(alloc, call_stmt.get_out_type_owner().at(i), field.type_owner_))) {
|
|
LOG_WARN("fail to alloc string", K(call_stmt.get_out_type_owner().at(i)), K(ret));
|
|
} else { /*do nothing*/ }
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(result_set.add_field_column(field))) {
|
|
LOG_WARN("fail to add field column to result_set.", K(ret));
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
field.cname_.assign(NULL, 0);
|
|
field.org_cname_.assign(NULL, 0);
|
|
field.dname_.assign(NULL, 0);
|
|
field.tname_.assign(NULL, 0);
|
|
field.org_tname_.assign(NULL, 0);
|
|
field.type_.reset();
|
|
field.type_.set_type(ObExtendType);
|
|
field.type_name_.assign(NULL, 0);
|
|
field.type_owner_.assign(NULL, 0);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
const int64_t question_marks_count = pctx->get_is_ps_rewrite_sql() ?
|
|
pctx->get_orig_question_mark_cnt() : stmt->get_query_ctx()->get_prepare_param_count();
|
|
if (OB_SUCC(ret) && is_ps_mode && question_marks_count > 0) { // param column is only needed in ps mode
|
|
if (OB_FAIL(result_set.reserve_param_columns(question_marks_count))) {
|
|
LOG_WARN("reserve param columns failed", K(ret), K(question_marks_count));
|
|
}
|
|
ObAnonymousBlockStmt *anonymous_stmt = NULL;
|
|
ObCallProcedureStmt *call_stmt = NULL;
|
|
if (stmt::T_ANONYMOUS_BLOCK == stmt->get_stmt_type()) {
|
|
CK (OB_NOT_NULL(anonymous_stmt = static_cast<ObAnonymousBlockStmt *>(stmt)));
|
|
OZ (result_set.reserve_field_columns(anonymous_stmt->get_out_idx().num_members()));
|
|
} else if (stmt::T_CALL_PROCEDURE == stmt->get_stmt_type()) {
|
|
CK (OB_NOT_NULL(call_stmt = static_cast<ObCallProcedureStmt *>(stmt)));
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < question_marks_count; ++i) {
|
|
ObField param_field;
|
|
param_field.type_.set_type(ObIntType); // @bug
|
|
param_field.cname_ = ObString::make_string("?");
|
|
if (OB_NOT_NULL(anonymous_stmt) && anonymous_stmt->get_out_idx().has_member(i)) {
|
|
ObField column_field;
|
|
column_field.type_.set_type(ObNullType);
|
|
OX (param_field.inout_mode_ = ObRoutineParamInOut::SP_PARAM_INOUT);
|
|
OZ (result_set.add_field_column(column_field),
|
|
K(i), K(question_marks_count), K(column_field));
|
|
} else if (OB_NOT_NULL(call_stmt) && call_stmt->is_out_param(i)) {
|
|
OX (param_field.inout_mode_ = ObRoutineParamInOut::SP_PARAM_INOUT);
|
|
}
|
|
OZ (result_set.add_param_column(param_field),
|
|
K(param_field), K(i), K(question_marks_count));
|
|
}
|
|
}
|
|
// for resolve returning_params and only work for ps_mode
|
|
// SQL: insert/update/delete ...returning expr1 ... into ?...
|
|
if (OB_SUCC(ret) && ObStmt::is_dml_write_stmt(stmt->get_stmt_type()) && is_ps_mode) {
|
|
del_upd_stmt = static_cast<ObDelUpdStmt *>(stmt);
|
|
if (del_upd_stmt->is_returning()) {
|
|
int64_t returning_param_num = del_upd_stmt->get_returning_exprs().count();
|
|
if (OB_FAIL(result_set.reserve_returning_param_column(returning_param_num))) {
|
|
LOG_WARN("reserve returning param columns failed", K(ret), K(question_marks_count));
|
|
}
|
|
for (int i = 0; OB_SUCC(ret) && i < returning_param_num; ++i) {
|
|
ObField param_field;
|
|
// type is mock, client not depend it
|
|
param_field.type_.set_type(ObIntType);
|
|
param_field.cname_ = ObString::make_string("?");
|
|
param_field.inout_mode_ = ObRoutineParamInOut::SP_PARAM_OUT;
|
|
OZ (result_set.add_returning_param_column(param_field), param_field, i, returning_param_num);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::fill_select_result_set(ObResultSet &result_set, ObSqlCtx *context, const bool is_ps_mode,
|
|
ObCollationType collation_type, const ObString &type_name,
|
|
ObStmt &basic_stmt, ObField &field)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSelectStmt *select_stmt = static_cast<ObSelectStmt *>(&basic_stmt);
|
|
if (select_stmt->has_select_into()) { // for select into, no rows return
|
|
// do nothing.
|
|
} else {
|
|
int64_t size = select_stmt->get_select_item_size();
|
|
common::ObIAllocator &alloc = result_set.get_mem_pool();
|
|
number::ObNumber number;
|
|
number.set_zero();
|
|
if (OB_FAIL(result_set.reserve_field_columns(size))) {
|
|
LOG_WARN("reserve field columns failed", K(ret), K(size));
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < size; ++i) {
|
|
const SelectItem &select_item = select_stmt->get_select_item(i);
|
|
LOG_DEBUG("select item info", K(select_item));
|
|
ObRawExpr *expr = select_item.expr_;
|
|
if (OB_UNLIKELY(NULL == expr)) {
|
|
ret = OB_ERR_ILLEGAL_ID;
|
|
LOG_WARN("fail to get expr", K(ret), K(i), K(size));
|
|
} else {
|
|
if (ob_is_string_or_lob_type(expr->get_data_type())
|
|
&& CS_TYPE_BINARY != expr->get_collation_type()
|
|
&& ObCharset::is_valid_collation(collation_type)) {
|
|
field.charsetnr_ = static_cast<uint16_t>(collation_type);
|
|
} else {
|
|
field.charsetnr_ = static_cast<uint16_t>(expr->get_collation_type());
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret) && expr->get_result_type().is_ext()) {
|
|
if ((expr->is_query_ref_expr() && static_cast<ObQueryRefRawExpr*>(expr)->is_cursor())
|
|
|| (expr->is_udf_expr() && static_cast<ObUDFRawExpr*>(expr)->get_is_return_sys_cursor())) {
|
|
if (OB_FAIL(ob_write_string(alloc, "SYS_REFCURSOR", field.type_name_))) {
|
|
LOG_WARN("fail to alloc string", K(i), K(field), K(ret));
|
|
}
|
|
} else if (NULL == context->secondary_namespace_ // pl resolve
|
|
&& NULL == context->session_info_->get_pl_context()) { // pl execute
|
|
ret = OB_NOT_SUPPORTED;
|
|
LOG_WARN("composite type use in pure sql context not supported!");
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
// Setup field Type and Accuracy
|
|
field.type_.set_type(expr->get_data_type());
|
|
field.accuracy_ = expr->get_accuracy();
|
|
field.flags_ = static_cast<uint16_t>(expr->get_result_flag());
|
|
// Setup Collation and Collation levl
|
|
if (ob_is_string_or_lob_type(static_cast<ObObjType>(expr->get_data_type()))
|
|
|| ob_is_raw(static_cast<ObObjType>(expr->get_data_type()))
|
|
|| ob_is_enum_or_set_type(static_cast<ObObjType>(expr->get_data_type()))) {
|
|
field.type_.set_collation_type(expr->get_collation_type());
|
|
field.type_.set_collation_level(expr->get_collation_level());
|
|
}
|
|
// Setup Scale
|
|
if (ObVarcharType == field.type_.get_type()) {
|
|
field.type_.set_varchar(type_name);
|
|
} else if (ObNumberType == field.type_.get_type()) {
|
|
field.type_.set_number(number);
|
|
}
|
|
if (!expr->get_result_type().is_ext() && OB_FAIL(expr->get_length_for_meta_in_bytes(field.length_))) {
|
|
LOG_WARN("get length failed", K(ret), KPC(expr));
|
|
}
|
|
}
|
|
|
|
// SELECT ITEM的alias name和expr name规则举例:
|
|
// SELECT field1+field2 AS f1, field1+3, "thanks", field2 AS f2, field3, "hello" as f4, field1+4 as f5 FROM t1
|
|
// "is_alias":true, "alias_name":"f1", "expr_name":"f1"
|
|
// "is_alias":false, "alias_name":"", "expr_name":"field1+3"
|
|
// "is_alias":false, "alias_name":"", "expr_name":", "thanks"",
|
|
// "is_alias":true, "alias_name":"f2", "expr_name":"f2", "column_name":"field2",
|
|
// "is_alias":true, "alias_name":"field3", "expr_name":"field3", "column_name":"field3",
|
|
// "is_alias":true, "alias_name":"f4", "expr_name":"f4"
|
|
// "is_alias":true, "alias_name":"f5", "expr_name":"f5"
|
|
//
|
|
ObCollationType field_names_collation =
|
|
ObCharset::is_valid_collation(collation_type) ? collation_type : CS_TYPE_UTF8MB4_BIN;
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(ObSQLUtils::copy_and_convert_string_charset(alloc, select_item.alias_name_, field.cname_,
|
|
CS_TYPE_UTF8MB4_BIN, field_names_collation))) {
|
|
LOG_WARN("fail to alloc string", K(select_item.alias_name_), K(ret));
|
|
} else {
|
|
field.is_hidden_rowid_ = select_item.is_hidden_rowid_;
|
|
LOG_TRACE("is_hidden_rowid", K(select_item));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
bool is_contain_column_ref = false;
|
|
if (expr->is_column_ref_expr()
|
|
|| T_FUN_SYS_CALC_UROWID == expr->get_expr_type()
|
|
|| T_FUN_SET_TO_STR == expr->get_expr_type()
|
|
|| T_FUN_ENUM_TO_STR == expr->get_expr_type()) {
|
|
const TableItem *table_item = NULL;
|
|
ObString column_name(OB_HIDDEN_LOGICAL_ROWID_COLUMN_NAME);
|
|
if ((T_FUN_SET_TO_STR != expr->get_expr_type() &&
|
|
T_FUN_ENUM_TO_STR != expr->get_expr_type()) &&
|
|
(T_FUN_SYS_CALC_UROWID == expr->get_expr_type() ||
|
|
ObCharset::case_insensitive_equal(OB_HIDDEN_LOGICAL_ROWID_COLUMN_NAME,
|
|
static_cast<ObColumnRefRawExpr *>(expr)->get_column_name()))) {
|
|
//Although the current implement of rowid does not use mock a column schema, it should
|
|
//be as normal column when displayed externally.
|
|
if (T_FUN_SYS_CALC_UROWID == expr->get_expr_type()) {
|
|
bool got_it = false;
|
|
for (int64_t i = 0; !got_it && OB_SUCC(ret) && i < expr->get_param_count(); ++i) {
|
|
ObRawExpr *param_expr = NULL;
|
|
if (OB_ISNULL(param_expr = expr->get_param_expr(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(param_expr), KPC(expr));
|
|
} else if (param_expr->is_column_ref_expr()) {
|
|
uint64_t table_id = static_cast<ObColumnRefRawExpr *>(param_expr)->get_table_id();
|
|
table_item = select_stmt->get_table_item_by_id(table_id);
|
|
got_it = true;
|
|
is_contain_column_ref = true;
|
|
} else {/*do nothing*/}
|
|
}
|
|
} else {//mock empty column expr for generate table
|
|
is_contain_column_ref = true;
|
|
ObColumnRefRawExpr *column_expr = static_cast<ObColumnRefRawExpr *>(expr);
|
|
table_item = select_stmt->get_table_item_by_id(column_expr->get_table_id());
|
|
}
|
|
} else {
|
|
ObColumnRefRawExpr *column_expr = NULL;
|
|
if (OB_FAIL(ObRawExprUtils::get_col_ref_expr_recursively(expr, column_expr))) {
|
|
LOG_WARN("failed to get col ref expr recursively", K(ret));
|
|
} else if (OB_NOT_NULL(column_expr)) {
|
|
is_contain_column_ref = true;
|
|
uint64_t table_id = column_expr->get_table_id();
|
|
uint64_t column_id = column_expr->get_column_id();
|
|
ColumnItem *column_item = select_stmt->get_column_item_by_id(table_id, column_id);
|
|
if (OB_ISNULL(column_item)) {
|
|
ret = OB_ERR_ILLEGAL_ID;
|
|
LOG_WARN("fail to get column item by id.", K(ret), K(table_id), K(column_id));
|
|
} else {
|
|
column_name = column_item->column_name_;
|
|
table_item = select_stmt->get_table_item_by_id(table_id);
|
|
if (column_expr->is_unique_key_column()) {
|
|
field.flags_ |= UNIQUE_KEY_FLAG;
|
|
}
|
|
if (column_expr->is_mul_key_column()) {
|
|
field.flags_ |= MULTIPLE_KEY_FLAG;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && is_contain_column_ref) {
|
|
if (OB_ISNULL(table_item)) {
|
|
ret = OB_ERR_ILLEGAL_ID;
|
|
LOG_WARN("fail to get table item by id.", K(ret));
|
|
} else if (OB_FAIL(ob_write_string(alloc,
|
|
column_name,
|
|
field.org_cname_))) {
|
|
LOG_WARN("fail to alloc", K(ret), K(column_name));
|
|
} else if (OB_FAIL(ObSQLUtils::copy_and_convert_string_charset(
|
|
alloc, table_item->database_name_, field.dname_,
|
|
CS_TYPE_UTF8MB4_BIN, field_names_collation))) {
|
|
LOG_WARN("fail to alloc string", K(ret), K(table_item->database_name_));
|
|
} else if (table_item->alias_name_.length() > 0) {
|
|
if (OB_FAIL(ObSQLUtils::copy_and_convert_string_charset(
|
|
alloc, table_item->alias_name_, field.tname_,
|
|
CS_TYPE_UTF8MB4_BIN, field_names_collation))) {
|
|
LOG_WARN("fail to alloc string", K(ret), K(table_item->alias_name_));
|
|
}
|
|
} else {
|
|
if (OB_FAIL(ObSQLUtils::copy_and_convert_string_charset(
|
|
alloc, table_item->table_name_, field.tname_,
|
|
CS_TYPE_UTF8MB4_BIN, field_names_collation))) {
|
|
LOG_WARN("fail to alloc string", K(ret), K(table_item->table_name_));
|
|
}
|
|
}
|
|
if (OB_FAIL(ob_write_string(alloc, table_item->table_name_, field.org_tname_))) {
|
|
LOG_WARN("fail to alloc string", K(ret), K(table_item->table_name_));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && !is_ps_mode) {
|
|
void *buf = NULL;
|
|
if (OB_ISNULL(buf = alloc.alloc(sizeof(ObParamedSelectItemCtx)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("failed to allocate memory", K(ret));
|
|
} else {
|
|
field.paramed_ctx_ = new(buf) ObParamedSelectItemCtx();
|
|
if (OB_FAIL(ob_write_string(alloc, select_item.paramed_alias_name_,
|
|
field.paramed_ctx_->paramed_cname_))) {
|
|
LOG_WARN("failed to copy paramed cname", K(ret));
|
|
} else if (OB_FAIL(field.paramed_ctx_->param_str_offsets_.assign(
|
|
select_item.questions_pos_))) {
|
|
LOG_WARN("failed to copy param_str_offsets_", K(ret));
|
|
} else if (OB_FAIL(field.paramed_ctx_->param_idxs_.assign(select_item.params_idx_))) {
|
|
LOG_WARN("failed to copy param idxs", K(ret));
|
|
} else {
|
|
field.paramed_ctx_->neg_param_idxs_ = select_item.neg_param_idx_;
|
|
field.paramed_ctx_->esc_str_flag_ = select_item.esc_str_flag_;
|
|
field.paramed_ctx_->need_check_dup_name_ = select_item.need_check_dup_name_;
|
|
// 如果投影列是一个column
|
|
field.paramed_ctx_->is_column_field_ = (T_REF_COLUMN == expr->get_expr_type());
|
|
field.is_paramed_select_item_ = true;
|
|
}
|
|
}
|
|
}
|
|
LOG_TRACE("column field info", K(field), K(select_item));
|
|
if (OB_FAIL(ret)) {
|
|
// do nothing
|
|
} else if (OB_FAIL(result_set.add_field_column(field))) {
|
|
LOG_WARN("failed to add field column", K(ret));
|
|
} else {
|
|
field.cname_.assign(NULL, 0);
|
|
field.org_cname_.assign(NULL, 0);
|
|
field.dname_.assign(NULL, 0);
|
|
field.tname_.assign(NULL, 0);
|
|
field.org_tname_.assign(NULL, 0);
|
|
field.type_.reset();
|
|
field.type_.set_type(ObExtendType);
|
|
field.paramed_ctx_ = NULL;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::fill_result_set(const ObPsStmtId stmt_id, const ObPsStmtInfo &stmt_info, ObResultSet &result)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
result.set_statement_id(stmt_id);
|
|
result.set_stmt_type(stmt_info.get_stmt_type());
|
|
const ObPsSqlMeta &sql_meta = stmt_info.get_ps_sql_meta();
|
|
result.set_p_param_fileds(const_cast<common::ParamsFieldIArray *>(&sql_meta.get_param_fields()));
|
|
result.set_p_column_fileds(const_cast<common::ParamsFieldIArray *>(&sql_meta.get_column_fields()));
|
|
//ObPsSqlMeta::const_column_iterator column_iter = sql_meta.column_begin();
|
|
//result.reserve_field_columns(sql_meta.get_column_size());
|
|
//for (; OB_SUCC(ret) && column_iter != sql_meta.column_end(); ++column_iter) {
|
|
//if (OB_ISNULL(column_iter) || OB_ISNULL(*column_iter)) {
|
|
//ret = OB_ERR_UNEXPECTED;
|
|
//LOG_WARN("column iter is null", K(ret), K(column_iter));
|
|
//} else if (OB_FAIL(result.add_field_column(**column_iter))) {
|
|
//LOG_WARN("add column field failed", K(ret));
|
|
//}
|
|
//}
|
|
|
|
//ObPsSqlMeta::const_param_iterator param_iter = sql_meta.param_begin();
|
|
//for (; OB_SUCC(ret) && param_iter != sql_meta.param_end(); ++param_iter) {
|
|
//if (OB_ISNULL(param_iter) || OB_ISNULL(param_iter)) {
|
|
//ret = OB_ERR_UNEXPECTED;
|
|
//LOG_WARN("param iter is null", K(ret), K(param_iter));
|
|
//} else if (OB_FAIL(result.add_param_column(**param_iter))) {
|
|
//LOG_WARN("add param field faield", K(ret));
|
|
//}
|
|
//}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::do_add_ps_cache(const PsCacheInfoCtx &info_ctx,
|
|
ObSchemaGetterGuard &schema_guard,
|
|
ObResultSet &result)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSQLSessionInfo &session = result.get_session();
|
|
ObPsCache *ps_cache = session.get_ps_cache();
|
|
uint64_t db_id = OB_INVALID_ID;
|
|
(void)session.get_database_id(db_id);
|
|
if (OB_ISNULL(ps_cache)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("ps plan cache should not be null", K(ret));
|
|
} else {
|
|
ObPsStmtItem *ps_stmt_item = NULL;
|
|
ObPsStmtInfo *ref_stmt_info = NULL;
|
|
bool duplicate_prepare = false;
|
|
// add stmt item
|
|
if (OB_FAIL(ps_cache->get_or_add_stmt_item(db_id,
|
|
info_ctx.normalized_sql_,
|
|
ps_stmt_item))) {
|
|
LOG_WARN("get or create stmt item faield", K(ret), K(db_id), K(info_ctx.normalized_sql_));
|
|
} else if (OB_FAIL(ps_cache->get_or_add_stmt_info(info_ctx,
|
|
result,
|
|
schema_guard,
|
|
ps_stmt_item,
|
|
ref_stmt_info))) {
|
|
LOG_WARN("get or create stmt info failed", K(ret), K(ps_stmt_item), K(db_id), K(info_ctx));
|
|
} else if (OB_ISNULL(ps_stmt_item) || OB_ISNULL(ref_stmt_info)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("stmt_item or stmt_info is NULL", K(ret), KP(ps_stmt_item), KP(ref_stmt_info));
|
|
}
|
|
if (NULL != ref_stmt_info) {
|
|
ref_stmt_info->set_is_sensitive_sql(info_ctx.is_sensitive_sql_);
|
|
}
|
|
//add session info
|
|
if (OB_SUCC(ret)) {
|
|
ObPsStmtId inner_stmt_id = ps_stmt_item->get_ps_stmt_id();
|
|
ObPsStmtId client_stmt_id = OB_INVALID_ID;
|
|
if (OB_FAIL(session.prepare_ps_stmt(inner_stmt_id,
|
|
ref_stmt_info,
|
|
client_stmt_id,
|
|
duplicate_prepare,
|
|
info_ctx.is_inner_sql_))) {
|
|
LOG_WARN("prepare_ps_stmt failed", K(ret), K(inner_stmt_id), K(client_stmt_id));
|
|
} else {
|
|
result.set_statement_id(client_stmt_id);
|
|
result.set_stmt_type(info_ctx.stmt_type_);
|
|
LOG_TRACE("add ps session info", K(ret), K(*ref_stmt_info), K(client_stmt_id),
|
|
K(*ps_stmt_item), K(session.get_sessid()));
|
|
}
|
|
}
|
|
if (OB_FAIL(ret) || duplicate_prepare) { //dec ref count
|
|
if (NULL != ps_stmt_item) {
|
|
if (NULL != ref_stmt_info) {
|
|
ObPsStmtId inner_stmt_id = ps_stmt_item->get_ps_stmt_id();
|
|
ps_cache->deref_stmt_info(inner_stmt_id); //需要决定是否摘除
|
|
}
|
|
ps_stmt_item->dec_ref_count_check_erase();
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::do_real_prepare(const ObString &sql,
|
|
ObSqlCtx &context,
|
|
ObResultSet &result,
|
|
bool is_inner_sql)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ParseResult parse_result;
|
|
ObStmt *basic_stmt = NULL;
|
|
stmt::StmtType stmt_type = stmt::T_NONE;
|
|
int64_t param_cnt = 0;
|
|
PsCacheInfoCtx info_ctx;
|
|
ObUDRItemMgr::UDRItemRefGuard item_guard;
|
|
ObIAllocator &allocator = result.get_mem_pool();
|
|
ObSQLSessionInfo &session = result.get_session();
|
|
ObExecContext &ectx = result.get_exec_context();
|
|
ObParser parser(allocator, session.get_sql_mode(), session.get_local_collation_connection());
|
|
ParseMode parse_mode = context.is_dbms_sql_ ? DBMS_SQL_MODE :
|
|
(context.is_dynamic_sql_ || !is_inner_sql) ? DYNAMIC_SQL_MODE :
|
|
session.is_for_trigger_package() ? TRIGGER_MODE : STD_MODE;
|
|
|
|
// normal ps sql also a dynamic sql, we adjust is_dynamic_sql_ for normal ps sql parser.
|
|
context.is_dynamic_sql_ = !context.is_dynamic_sql_ ? !is_inner_sql : context.is_dynamic_sql_;
|
|
|
|
bool is_from_pl = (NULL != context.secondary_namespace_ || result.is_simple_ps_protocol());
|
|
ObPsPrepareStatusGuard ps_status_guard(session, is_from_pl);
|
|
ObPlanCacheCtx pc_ctx(sql, true, /*is_ps_mode*/
|
|
allocator, context, ectx, session.get_effective_tenant_id());
|
|
ParamStore param_store( (ObWrapperAllocator(&allocator)) );
|
|
omt::ObTenantConfigGuard tenant_config(TENANT_CONF(session.get_effective_tenant_id()));
|
|
pc_ctx.set_is_inner_sql(is_inner_sql);
|
|
|
|
CHECK_COMPATIBILITY_MODE(context.session_info_);
|
|
|
|
if (!tenant_config.is_valid()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("tenant config is invalid", K(ret));
|
|
} else if (OB_ISNULL(context.session_info_) || OB_ISNULL(context.schema_guard_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("session info is NULL", K(ret));
|
|
} else if (OB_FAIL(parser.parse(sql,
|
|
parse_result,
|
|
parse_mode,
|
|
false/*is_batched_multi_stmt_split_on*/))) {
|
|
LOG_WARN("generate syntax tree failed", K(sql), K(ret));
|
|
} else if (is_mysql_mode()
|
|
&& ObSQLUtils::is_mysql_ps_not_support_stmt(parse_result)) {
|
|
ret = OB_ER_UNSUPPORTED_PS;
|
|
LOG_WARN("This command is not supported in the prepared statement protocol yet", K(ret));
|
|
}
|
|
|
|
OZ (ObResolverUtils::resolve_stmt_type(parse_result, stmt_type));
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (result.is_simple_ps_protocol() // simple_ps_protocol only do parse
|
|
// for anonymous block, only parser in prepare of preexecute
|
|
|| (stmt::T_ANONYMOUS_BLOCK == stmt_type
|
|
&& context.is_prepare_protocol_
|
|
&& context.is_prepare_stage_
|
|
&& context.is_pre_execute_)) {
|
|
param_cnt = parse_result.question_mark_ctx_.count_;
|
|
info_ctx.normalized_sql_ = sql;
|
|
if (stmt::T_ANONYMOUS_BLOCK == stmt_type
|
|
&& context.is_prepare_protocol_
|
|
&& context.is_prepare_stage_
|
|
&& context.is_pre_execute_) {
|
|
OZ (result.reserve_param_columns(param_cnt));
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < param_cnt; ++i) {
|
|
ObField param_field;
|
|
param_field.type_.set_type(ObIntType);
|
|
param_field.cname_ = ObString::make_string("?");
|
|
OZ (result.add_param_column(param_field), K(param_field), K(i), K(param_cnt));
|
|
}
|
|
}
|
|
} else {
|
|
if (context.is_dynamic_sql_ && !context.is_dbms_sql_) {
|
|
parse_result.input_sql_ = parse_result.no_param_sql_;
|
|
parse_result.input_sql_len_ = parse_result.no_param_sql_len_;
|
|
}
|
|
if (OB_FAIL(generate_stmt(parse_result, NULL, context, allocator, result, basic_stmt))) {
|
|
LOG_WARN("generate stmt failed", K(ret));
|
|
} else if (!is_from_pl
|
|
&& !is_inner_sql
|
|
&& tenant_config->enable_user_defined_rewrite_rules
|
|
&& OB_FAIL(ObUDRUtils::match_udr_item(sql, session, allocator, item_guard))) {
|
|
LOG_WARN("failed to match rewrite rule", K(ret));
|
|
} else if (ObStmt::is_dml_stmt(stmt_type)
|
|
&& NULL == item_guard.get_ref_obj()
|
|
&& !ObStmt::is_show_stmt(stmt_type)
|
|
&& !is_inner_sql
|
|
&& !is_from_pl
|
|
&& !(ObStmt::is_dml_write_stmt(stmt_type) && // returning into from oci not need parameterization
|
|
static_cast<ObDelUpdStmt*>(basic_stmt)->get_returning_into_exprs().count() > 0)) {
|
|
bool is_transform_outline = false;
|
|
if (OB_FAIL(ObSqlParameterization::parameterize_syntax_tree(allocator,
|
|
is_transform_outline,
|
|
pc_ctx,
|
|
parse_result.result_tree_,
|
|
param_store,
|
|
session.get_local_collation_connection()))) {
|
|
LOG_WARN("parameterize syntax tree failed", K(ret));
|
|
} else if (!pc_ctx.ps_need_parameterized_) {
|
|
pc_ctx.fixed_param_idx_.reset();
|
|
pc_ctx.fp_result_.raw_params_.reset();
|
|
} else {
|
|
info_ctx.no_param_sql_ = pc_ctx.sql_ctx_.spm_ctx_.bl_key_.constructed_sql_;
|
|
}
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_ISNULL(basic_stmt)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("generate stmt success, but stmt is NULL", K(ret));
|
|
} else if (OB_ISNULL(basic_stmt->get_query_ctx())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("query ctx is null", K(ret));
|
|
} else if (stmt::T_CALL_PROCEDURE == basic_stmt->get_stmt_type()
|
|
&& FALSE_IT(result.set_cmd(dynamic_cast<ObICmd*>(basic_stmt)))) {
|
|
} else if (OB_FAIL(fill_result_set(result, &context, true, *basic_stmt))) {
|
|
LOG_WARN("Failed to fill result set", K(ret));
|
|
} else if (OB_ISNULL(result.get_param_fields())) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(result.get_param_fields()), K(ret));
|
|
} else {
|
|
param_cnt = result.get_param_fields()->count();
|
|
stmt_type = basic_stmt->get_stmt_type();
|
|
//如果是内部sql, 比如pl内部sql, 需要使用格式化后的文本串,
|
|
//因为需要将pl中sql的变量替换为标准的ps文本进行硬解析
|
|
//而外部请求的ps文本不能格式化, 因为在解析ps execute包时需要进行checksum校验,
|
|
//需要确保prepare的文本与客户端发过来的一致
|
|
if (is_inner_sql) {
|
|
// pl
|
|
info_ctx.normalized_sql_ = basic_stmt->get_query_ctx()->get_sql_stmt();
|
|
} else if (result.is_returning() && ObStmt::is_dml_write_stmt(stmt_type)) {
|
|
info_ctx.normalized_sql_ = sql;
|
|
info_ctx.no_param_sql_ = basic_stmt->get_query_ctx()->get_sql_stmt();
|
|
} else {
|
|
info_ctx.normalized_sql_ = sql;
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (basic_stmt->is_insert_stmt() || basic_stmt->is_update_stmt() || basic_stmt->is_delete_stmt()) {
|
|
ObDelUpdStmt *dml_stmt = static_cast<ObDelUpdStmt*>(basic_stmt);
|
|
if (dml_stmt->get_returning_into_exprs().count() != 0 && dml_stmt->is_returning()) {
|
|
info_ctx.num_of_returning_into_ = dml_stmt->get_returning_into_exprs().count();
|
|
}
|
|
}
|
|
}
|
|
|
|
LOG_INFO("generate new stmt", K(ret), K(param_cnt), K(stmt_type), K(info_ctx.no_param_sql_),
|
|
K(info_ctx.normalized_sql_), K(sql), K(info_ctx.num_of_returning_into_));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
info_ctx.param_cnt_ = param_cnt;
|
|
info_ctx.stmt_type_ = stmt_type;
|
|
info_ctx.is_inner_sql_ = is_inner_sql;
|
|
info_ctx.is_sensitive_sql_ = context.is_sensitive_;
|
|
info_ctx.raw_params_ = &pc_ctx.fp_result_.raw_params_;
|
|
info_ctx.fixed_param_idx_ = &pc_ctx.fixed_param_idx_;
|
|
info_ctx.raw_sql_.assign_ptr(sql.ptr(), sql.length());
|
|
if (OB_FAIL(do_add_ps_cache(info_ctx, *context.schema_guard_, result))) {
|
|
LOG_WARN("add to ps plan cache failed",
|
|
K(ret), K(info_ctx.normalized_sql_), K(param_cnt));
|
|
}
|
|
}
|
|
//if the error code is ob_timeout, we add more error info msg for dml query.
|
|
if (OB_TIMEOUT == ret &&
|
|
parse_result.result_tree_ != NULL &&
|
|
parse_result.result_tree_->children_ != NULL &&
|
|
parse_result.result_tree_->num_child_ >= 1 &&
|
|
(parse_result.result_tree_->children_[0]->type_ == T_EXPLAIN ||
|
|
IS_DML_STMT(parse_result.result_tree_->children_[0]->type_) ||
|
|
IS_SHOW_STMT(parse_result.result_tree_->children_[0]->type_))) {
|
|
LOG_USER_ERROR(OB_TIMEOUT, THIS_WORKER.get_timeout_ts() - session.get_query_start_time());
|
|
}
|
|
LOG_INFO("add ps cache", K(info_ctx.normalized_sql_), K(param_cnt), K(ret));
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::handle_ps_prepare(const ObString &stmt,
|
|
ObSqlCtx &context,
|
|
ObResultSet &result,
|
|
bool is_inner_sql)
|
|
{
|
|
// open_cursors is 0 to indicate a special state, no limit is set
|
|
#define NEED_CHECK_SESS_MAX_PS_HANDLE_LIMIT(v) (0 == v ? false : true)
|
|
int ret = OB_SUCCESS;
|
|
ObString cur_query;
|
|
// trimed_stmt仅用于query empty检查, prepare语句需要用原始语句, 避免checksum不一致
|
|
ObString trimed_stmt = const_cast<ObString &>(stmt).trim();
|
|
if (trimed_stmt.empty()) {
|
|
ret = OB_ERR_EMPTY_QUERY;
|
|
LOG_WARN("query is empty", K(ret));
|
|
} else if (OB_FAIL(init_result_set(context, result))) {
|
|
LOG_WARN("failed to init result set", K(ret));
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
ObSQLSessionInfo &session = result.get_session();
|
|
ObPsCache *ps_cache = session.get_ps_cache();
|
|
ObExecContext &ectx = result.get_exec_context();
|
|
ObIAllocator &allocator = result.get_mem_pool();
|
|
ObPhysicalPlanCtx *pctx = ectx.get_physical_plan_ctx();
|
|
ObSchemaGetterGuard *schema_guard = context.schema_guard_;
|
|
ectx.set_is_ps_prepare_stage(true);
|
|
|
|
#ifndef NDEBUG
|
|
LOG_INFO("Begin to handle prepare stmtement", K(session.get_sessid()), K(stmt));
|
|
#endif
|
|
|
|
if (OB_ISNULL(ps_cache) || OB_ISNULL(pctx) || OB_ISNULL(schema_guard)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_ERROR("physical plan context or ps plan cache is NULL or schema_guard is null",
|
|
K(ret), K(pctx), K(ps_cache));
|
|
} else if (OB_FAIL(ob_write_string(allocator, session.get_current_query_string(), cur_query))) {
|
|
LOG_WARN("failed to write string", K(ret));
|
|
} else if (OB_FAIL(session.store_query_string(trimed_stmt))) {
|
|
LOG_WARN("store query string fail", K(ret));
|
|
} else {
|
|
bool need_do_real_prepare = false;
|
|
uint64_t db_id = OB_INVALID_ID;
|
|
(void)session.get_database_id(db_id);
|
|
ObPsStmtId inner_stmt_id = OB_INVALID_STMT_ID;
|
|
ObPsStmtId client_stmt_id = OB_INVALID_STMT_ID;
|
|
ObPsStmtInfo *stmt_info = NULL;
|
|
ObPsStmtItem *stmt_item = NULL;
|
|
bool duplicate_prepare = false;
|
|
bool is_expired = false;
|
|
int64_t open_cursors_limit = 0;
|
|
int64_t cur_ps_handle_size = session.get_ps_session_info_size();
|
|
omt::ObTenantConfigGuard tenant_config(TENANT_CONF(session.get_effective_tenant_id()));
|
|
if (!tenant_config.is_valid()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("tenant config is invalid", K(ret));
|
|
} else if (FALSE_IT(open_cursors_limit = tenant_config->open_cursors)) {
|
|
} else if (!is_inner_sql
|
|
&& NEED_CHECK_SESS_MAX_PS_HANDLE_LIMIT(open_cursors_limit)
|
|
&& cur_ps_handle_size >= open_cursors_limit) {
|
|
ret = OB_ERR_OPEN_CURSORS_EXCEEDED;
|
|
LOG_WARN("exceeds the maximum number of ps handles allowed to open on the session",
|
|
K(ret), K(cur_ps_handle_size), K(open_cursors_limit));
|
|
} else if (NULL != context.secondary_namespace_ || result.is_simple_ps_protocol()) {
|
|
// pl发起的sql解析, 由于每次需要计算依赖对象等额外参数, 因此需要做do_real_prepare
|
|
need_do_real_prepare = true;
|
|
if (REACH_TIME_INTERVAL(1000000)) {
|
|
LOG_INFO("need do real prepare",
|
|
K(db_id), K(stmt), K(need_do_real_prepare), K(context.secondary_namespace_),
|
|
K(result.is_simple_ps_protocol()));
|
|
}
|
|
} else if (OB_FAIL(ps_cache->ref_stmt_item(db_id, stmt, stmt_item))) {
|
|
if (OB_HASH_NOT_EXIST == ret) {
|
|
ret = OB_SUCCESS;
|
|
need_do_real_prepare = true;
|
|
if (REACH_TIME_INTERVAL(1000000)) {
|
|
LOG_INFO("stmt id not exist", K(db_id), K(stmt), K(need_do_real_prepare));
|
|
}
|
|
} else {
|
|
LOG_WARN("fail to get stmt id", K(ret), K(db_id), K(stmt));
|
|
}
|
|
} else if (OB_ISNULL(stmt_item)
|
|
|| OB_INVALID_STMT_ID == (inner_stmt_id = stmt_item->get_ps_stmt_id())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("stmt id is invalid", K(ret), K(inner_stmt_id), K(db_id), K(stmt), K(stmt_item));
|
|
} else if (OB_FAIL(ps_cache->ref_stmt_info(inner_stmt_id, stmt_info))) {
|
|
//inc stmt_info ref for session
|
|
if (OB_HASH_NOT_EXIST == ret) {
|
|
need_do_real_prepare = true;
|
|
if (REACH_TIME_INTERVAL(1000000)) {
|
|
LOG_INFO("stmt info not exist", K(db_id), K(stmt), K(inner_stmt_id), K(ret));
|
|
}
|
|
ret = OB_SUCCESS;
|
|
} else {
|
|
LOG_WARN("fail to get stmt info", K(ret), K(db_id), K(stmt), K(inner_stmt_id));
|
|
}
|
|
} else if (OB_ISNULL(stmt_info)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("stmt info is null", K(ret), K(inner_stmt_id));
|
|
//check stmt_info whether expired, if expired, do nothing
|
|
} else if (OB_FAIL(ps_cache->check_schema_version(*context.schema_guard_,
|
|
*stmt_info,
|
|
is_expired))) {
|
|
LOG_WARN("fail to check schema version", K(ret));
|
|
} else if (is_expired) {
|
|
ObPsSqlKey ps_sql_key;
|
|
stmt_info->set_is_expired();
|
|
ps_sql_key.set_db_id(stmt_info->get_db_id());
|
|
ps_sql_key.set_ps_sql(stmt_info->get_ps_sql());
|
|
if (OB_FAIL(ps_cache->erase_stmt_item(inner_stmt_id, ps_sql_key))) {
|
|
LOG_WARN("fail to erase stmt item", K(ret), K(*stmt_info));
|
|
}
|
|
need_do_real_prepare = true;
|
|
} else if (OB_FAIL(session.prepare_ps_stmt(inner_stmt_id,
|
|
stmt_info,
|
|
client_stmt_id,
|
|
duplicate_prepare,
|
|
is_inner_sql))) {
|
|
LOG_WARN("add ps session info failed", K(ret), K(inner_stmt_id), K(client_stmt_id));
|
|
} else if (OB_FAIL(fill_result_set(client_stmt_id, *stmt_info, result))) {
|
|
//prepare ps stmt已成功,失败此处需close
|
|
IGNORE_RETURN session.close_ps_stmt(client_stmt_id);
|
|
LOG_WARN("fill result set failed", K(ret), K(client_stmt_id));
|
|
}
|
|
LOG_DEBUG("prepare done", K(ret), K(need_do_real_prepare), K(duplicate_prepare));
|
|
if (OB_FAIL(ret)
|
|
|| need_do_real_prepare
|
|
|| duplicate_prepare) {
|
|
if (NULL != stmt_item) {
|
|
stmt_item->dec_ref_count_check_erase();
|
|
}
|
|
if (NULL != stmt_info) {
|
|
ps_cache->deref_stmt_info(inner_stmt_id); //需要决定是否摘除
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && need_do_real_prepare) {
|
|
if (OB_FAIL(do_real_prepare(stmt, context, result, is_inner_sql))) {
|
|
LOG_WARN("do_real_prepare failed", K(ret));
|
|
}
|
|
} else if (OB_SUCC(ret) && NULL != stmt_info) {
|
|
context.is_sensitive_ = stmt_info->get_is_sensitive_sql();
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (false == need_do_real_prepare) {
|
|
ps_cache->inc_access_and_hit_count();
|
|
} else {
|
|
// 没有命中ps cache的情况下,只增加access count
|
|
// 这里的判断逻辑会导致pl每次prepare都只是增加access count,不增加hit_count
|
|
// 所以从ps相关虚拟表中看到的ps cache命中率会比较低
|
|
ps_cache->inc_access_count();
|
|
}
|
|
}
|
|
}
|
|
OZ (session.store_query_string(cur_query));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::add_param_to_param_store(const ObObjParam ¶m,
|
|
ParamStore ¶m_store)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (lib::is_oracle_mode()
|
|
&& ( (param.is_varchar() && 0 == param.get_varchar().length())
|
|
|| (param.is_char() && 0 == param.get_char().length())
|
|
|| (param.is_nstring() && 0 == param.get_string_len()) )) {
|
|
const_cast<ObObjParam &>(param).set_null();
|
|
const_cast<ObObjParam &>(param).set_param_meta();
|
|
}
|
|
if (OB_FAIL(param_store.push_back(param))) {
|
|
LOG_WARN("pushback param failed", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::construct_param_store_from_ps_param(const ObPlanCacheCtx &phy_ctx,
|
|
ParamStore ¶m_store)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(param_store.reserve(phy_ctx.fp_result_.ps_params_.count()))) {
|
|
LOG_WARN("failed to reserve array", K(ret));
|
|
}
|
|
for (int i = 0; OB_SUCC(ret) && i < phy_ctx.fp_result_.ps_params_.count(); ++i) {
|
|
const common::ObObjParam *param = phy_ctx.fp_result_.ps_params_.at(i);
|
|
if (OB_FAIL(add_param_to_param_store(*param, param_store))) {
|
|
LOG_WARN("failed to add param to param store", K(ret));
|
|
}
|
|
LOG_TRACE("ps param is", KPC(param), K(i));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool ObSql::is_exist_in_fixed_param_idx(const int64_t idx,
|
|
const ObIArray<int64_t> &fixed_param_idx)
|
|
{
|
|
bool bool_ret = false;
|
|
for (int i = 0; i < fixed_param_idx.count(); ++i) {
|
|
if (idx == fixed_param_idx.at(i)) {
|
|
bool_ret = true;
|
|
break;
|
|
}
|
|
}
|
|
return bool_ret;
|
|
}
|
|
|
|
int ObSql::construct_ps_param_store(const ParamStore ¶ms,
|
|
const ParamStore &fixed_params,
|
|
const ObIArray<int64_t> &fixed_params_idx,
|
|
ParamStore ¶m_store)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t param_idx = 0;
|
|
int64_t fixed_param_idx = 0;
|
|
int64_t param_count = params.count() + fixed_params.count();
|
|
if (fixed_params.count() != fixed_params_idx.count()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("the number of fixed param does not match", K(fixed_params), K(fixed_params_idx));
|
|
} else if (OB_FAIL(param_store.reserve(param_count))) {
|
|
LOG_WARN("failed to reserve array", K(ret), K(param_count));
|
|
}
|
|
for (int i = 0; OB_SUCC(ret) && i < param_count; ++i) {
|
|
if (is_exist_in_fixed_param_idx(i, fixed_params_idx)) {
|
|
if (fixed_param_idx >= fixed_params.count()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("Invalid index", K(fixed_param_idx), K(fixed_params));
|
|
} else if (OB_FAIL(add_param_to_param_store(fixed_params.at(fixed_param_idx),
|
|
param_store))) {
|
|
LOG_WARN("failed to add param to param store", K(ret));
|
|
} else {
|
|
LOG_TRACE("ps param is", K(fixed_params.at(fixed_param_idx)), K(i));
|
|
}
|
|
++fixed_param_idx;
|
|
} else {
|
|
if (param_idx >= params.count()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("Invalid index", K(param_idx), K(params));
|
|
} else if (OB_FAIL(add_param_to_param_store(params.at(param_idx), param_store))) {
|
|
LOG_WARN("failed to add param to param store", K(ret));
|
|
} else {
|
|
LOG_TRACE("ps param is", K(params.at(param_idx)), K(i));
|
|
}
|
|
++param_idx;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::construct_param_store(const ParamStore ¶ms,
|
|
ParamStore ¶m_store)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(param_store.reserve(params.count()))) {
|
|
LOG_WARN("failed to reserve array", K(ret));
|
|
}
|
|
for (int i = 0; OB_SUCC(ret) && i < params.count(); ++i) {
|
|
if (OB_FAIL(add_param_to_param_store(params.at(i), param_store))) {
|
|
LOG_WARN("failed to add param to param store", K(ret));
|
|
}
|
|
LOG_TRACE("ps param is", K(params.at(i)), K(i));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::construct_ps_param(const ParamStore ¶ms,
|
|
ObPlanCacheCtx &phy_ctx)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
phy_ctx.fp_result_.ps_params_.reset();
|
|
phy_ctx.fp_result_.ps_params_.set_allocator(&phy_ctx.allocator_);
|
|
phy_ctx.fp_result_.ps_params_.set_capacity(params.count());
|
|
for (int i = 0; OB_SUCC(ret) && i < params.count(); ++i) {
|
|
if (OB_FAIL(phy_ctx.fp_result_.ps_params_.push_back(¶ms.at(i)))) {
|
|
LOG_WARN("add ps param failed", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::clac_fixed_param_store(const stmt::StmtType stmt_type,
|
|
const ObIArray<int64_t> &raw_params_idx,
|
|
const ObIArray<ObPCParam *> &raw_params,
|
|
ObIAllocator &allocator,
|
|
ObSQLSessionInfo &session,
|
|
ParamStore &fixed_param_store)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObCollationType collation_connection = static_cast<ObCollationType>(
|
|
session.get_local_collation_connection());
|
|
ObString literal_prefix;
|
|
ObObjParam value;
|
|
const bool is_paramlize = false;
|
|
int64_t server_collation = CS_TYPE_INVALID;
|
|
if (raw_params.empty()) {
|
|
// do nothing
|
|
} else if (raw_params_idx.count() != raw_params.count()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("the number of fixed param does not match",
|
|
K(raw_params_idx.count()), K(raw_params.count()));
|
|
} else if (OB_FAIL(fixed_param_store.reserve(raw_params_idx.count()))) {
|
|
LOG_WARN("failed to reserve array", K(ret), K(raw_params_idx.count()));
|
|
} else if (lib::is_oracle_mode() && OB_FAIL(
|
|
session.get_sys_variable(share::SYS_VAR_COLLATION_SERVER, server_collation))) {
|
|
LOG_WARN("get sys variable failed", K(ret));
|
|
}
|
|
for (int i = 0; OB_SUCC(ret) && i < raw_params.count(); ++i) {
|
|
value.reset();
|
|
ParseNode *raw_param = NULL;;
|
|
if (OB_ISNULL(raw_params.at(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("raw param is null", K(ret));
|
|
} else if (OB_ISNULL(raw_param = raw_params.at(i)->node_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("node is null", K(ret));
|
|
} else if (OB_FAIL(ObResolverUtils::resolve_const(raw_param,
|
|
stmt_type,
|
|
allocator,
|
|
collation_connection,
|
|
session.get_nls_collation_nation(),
|
|
session.get_timezone_info(),
|
|
value,
|
|
is_paramlize,
|
|
literal_prefix,
|
|
session.get_actual_nls_length_semantics(),
|
|
static_cast<ObCollationType>(server_collation),
|
|
NULL, session.get_sql_mode()))) {
|
|
SQL_PC_LOG(WARN, "fail to resolve const", K(ret));
|
|
} else if (OB_FAIL(add_param_to_param_store(value, fixed_param_store))) {
|
|
LOG_WARN("failed to add param to param store", K(ret), K(value), K(fixed_param_store));
|
|
} else {
|
|
LOG_TRACE("fixed param is", K(value));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::init_execute_params_for_ab(ObIAllocator &allocator,
|
|
const ParamStore ¶ms_store,
|
|
ParamStore *&first_group_params)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(first_group_params = static_cast<ParamStore *>(allocator.alloc(sizeof(ParamStore))))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("failed to allocate memory", K(ret));
|
|
} else if (FALSE_IT(first_group_params = new(first_group_params)ParamStore(ObWrapperAllocator(allocator)))) {
|
|
// do nothing
|
|
} else if (OB_FAIL(ObPlanCacheValue::get_one_group_params(0, params_store, *first_group_params))) {
|
|
LOG_WARN("fail to get the first group paramsters", K(ret));
|
|
} else {
|
|
for (int64_t i = 0; i < first_group_params->count(); i++) {
|
|
ObObjParam &obj_param = first_group_params->at(i);
|
|
obj_param.get_param_flag().is_batch_parameter_ = true;
|
|
}
|
|
}
|
|
LOG_DEBUG("print first_group_params", K(ret), KPC(first_group_params));
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::reconstruct_ps_params_store(ObIAllocator &allocator,
|
|
ObSqlCtx &context,
|
|
const ParamStore &origin_params,
|
|
const ParamStore &fixed_params,
|
|
ObPsStmtInfo *ps_info,
|
|
ParamStore &ps_params,
|
|
ParamStore *&ps_ab_params)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ParamStore *first_group_params = NULL;
|
|
if (context.multi_stmt_item_.is_batched_multi_stmt()) {
|
|
if (OB_FAIL(init_execute_params_for_ab(allocator, origin_params, first_group_params))) {
|
|
LOG_WARN("fail to init first batch params", K(ret), K(origin_params));
|
|
} else if (OB_FAIL(construct_ps_param_store(*first_group_params,
|
|
fixed_params,
|
|
ps_info->get_raw_params_idx(),
|
|
ps_params))) {
|
|
LOG_WARN("construct param store failed", K(ret));
|
|
} else if (OB_ISNULL(ps_ab_params = static_cast<ParamStore *>(allocator.alloc(sizeof(ParamStore))))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("failed to allocate memory", K(ret));
|
|
} else if (FALSE_IT(ps_ab_params = new(ps_ab_params)ParamStore(ObWrapperAllocator(allocator)))) {
|
|
// do nothing
|
|
} else if (OB_FAIL(construct_ps_param_store(origin_params,
|
|
fixed_params,
|
|
ps_info->get_raw_params_idx(),
|
|
*ps_ab_params))) {
|
|
LOG_WARN("construct param store failed", K(ret));
|
|
}
|
|
} else if (OB_FAIL(construct_ps_param_store(origin_params,
|
|
fixed_params,
|
|
ps_info->get_raw_params_idx(),
|
|
ps_params))) {
|
|
LOG_WARN("construct param store failed", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::handle_ps_execute(const ObPsStmtId client_stmt_id,
|
|
const stmt::StmtType stmt_type,
|
|
const ParamStore ¶ms,
|
|
ObSqlCtx &context,
|
|
ObResultSet &result,
|
|
bool is_inner_sql)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ParamStore *ps_ab_params = NULL;
|
|
int get_plan_err = OB_SUCCESS;
|
|
context.is_prepare_protocol_ = true;
|
|
ObPsStmtId inner_stmt_id = client_stmt_id;
|
|
context.stmt_type_ = stmt_type;
|
|
|
|
// normal ps execute sql also a dynamic sql, here we adjust is_dynamic_sql_.
|
|
context.is_dynamic_sql_ = !context.is_dynamic_sql_ ? !is_inner_sql : context.is_dynamic_sql_;
|
|
|
|
ObIAllocator &allocator = result.get_mem_pool();
|
|
ObSQLSessionInfo &session = result.get_session();
|
|
ObExecContext &ectx = result.get_exec_context();
|
|
ectx.get_das_ctx().get_schema_guard() = context.schema_guard_;
|
|
ParamStore fixed_params( (ObWrapperAllocator(allocator)) );
|
|
ParamStore ps_params( (ObWrapperAllocator(allocator)) );
|
|
ObPsCache *ps_cache = session.get_ps_cache();
|
|
ObPlanCache *plan_cache = session.get_plan_cache();
|
|
bool use_plan_cache = session.get_local_ob_enable_plan_cache();
|
|
ObPhysicalPlanCtx *pctx = ectx.get_physical_plan_ctx();
|
|
ObSchemaGetterGuard *schema_guard = context.schema_guard_;
|
|
int64_t origin_params_count = params.count();
|
|
if (OB_ISNULL(ps_cache) || OB_ISNULL(pctx) || OB_ISNULL(schema_guard) || OB_ISNULL(plan_cache)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_ERROR("physical plan context or ps plan cache is NULL or schema_guard is null",
|
|
K(ret), K(pctx), K(ps_cache));
|
|
} else if (!is_inner_sql && OB_FAIL(session.get_inner_ps_stmt_id(client_stmt_id,
|
|
inner_stmt_id))) {
|
|
LOG_WARN("get_inner_ps_stmt_id failed", K(ret), K(client_stmt_id), K(inner_stmt_id));
|
|
} else {
|
|
context.statement_id_ = inner_stmt_id;
|
|
ObPsStmtInfoGuard guard;
|
|
ObPsStmtInfo *ps_info = NULL;
|
|
pctx->set_original_param_cnt(origin_params_count);
|
|
pctx->set_orig_question_mark_cnt(origin_params_count);
|
|
if (OB_FAIL(ps_cache->get_stmt_info_guard(inner_stmt_id, guard))) {
|
|
LOG_WARN("get stmt info guard failed", K(ret), K(inner_stmt_id));
|
|
} else if (OB_ISNULL(ps_info = guard.get_stmt_info())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get stmt info is null", K(ret));
|
|
} else if (ps_info->get_question_mark_count() != origin_params_count) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("Incorrect arguments to execute",
|
|
K(ps_info->get_question_mark_count()),
|
|
K(ps_info->get_ps_sql()),
|
|
K(origin_params_count), K(ret));
|
|
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "execute");
|
|
} else if (OB_FAIL(clac_fixed_param_store(stmt_type,
|
|
ps_info->get_raw_params_idx(),
|
|
ps_info->get_fixed_raw_params(),
|
|
allocator,
|
|
session,
|
|
fixed_params))) {
|
|
LOG_WARN("failed to calc fixed param store", K(ret));
|
|
} else if (OB_FAIL(reconstruct_ps_params_store(
|
|
allocator, context, params, fixed_params, ps_info, ps_params, ps_ab_params))) {
|
|
LOG_WARN("fail to reconstruct_ps_params_store", K(ret));
|
|
} else if (context.multi_stmt_item_.is_batched_multi_stmt() &&
|
|
OB_ISNULL(ps_ab_params)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("ps_ab_params_store is null", K(ret));
|
|
} else if (OB_FAIL(construct_param_store(ps_params, pctx->get_param_store_for_update()))) {
|
|
LOG_WARN("construct param store failed", K(ret));
|
|
} else {
|
|
const ObString &sql = !ps_info->get_no_param_sql().empty() ? ps_info->get_no_param_sql() : ps_info->get_ps_sql();
|
|
context.cur_sql_ = sql;
|
|
#ifndef NDEBUG
|
|
LOG_INFO("Begin to handle execute stmtement", K(session.get_sessid()), K(sql));
|
|
#endif
|
|
|
|
if (!ps_info->get_fixed_raw_params().empty()) {
|
|
pctx->set_is_ps_rewrite_sql();
|
|
}
|
|
if (OB_FAIL(session.store_query_string(sql))) {
|
|
LOG_WARN("store query string fail", K(ret));
|
|
} else if (FALSE_IT(generate_ps_sql_id(sql, context))) {
|
|
} else if (OB_LIKELY(ObStmt::is_dml_stmt(stmt_type))) {
|
|
//if plan not exist, generate plan
|
|
ObPlanCacheCtx pc_ctx(sql, true, /*is_ps_mode*/
|
|
allocator, context, ectx, session.get_effective_tenant_id());
|
|
pc_ctx.fp_result_.pc_key_.key_id_ = inner_stmt_id;
|
|
pc_ctx.normal_parse_const_cnt_ = ps_params.count();
|
|
context.spm_ctx_.bl_key_.db_id_ = session.get_database_id();
|
|
pc_ctx.set_is_ps_execute_stage();
|
|
pc_ctx.set_is_inner_sql(is_inner_sql);
|
|
pc_ctx.ab_params_ = ps_ab_params;
|
|
if (OB_FAIL(construct_ps_param(ps_params, pc_ctx))) {
|
|
LOG_WARN("construct_ps_param failed", K(ret));
|
|
} else {
|
|
if (!use_plan_cache) {
|
|
/*do nothing*/
|
|
} else if (OB_FAIL(pc_get_plan_and_fill_result(pc_ctx, result, get_plan_err,
|
|
ectx.get_need_disconnect_for_update()))) {
|
|
LOG_DEBUG("fail to get plan", K(ret));
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {//do nothing
|
|
} else if (!result.get_is_from_plan_cache()) {
|
|
pctx->set_original_param_cnt(origin_params_count);
|
|
pctx->get_param_store_for_update().reset();
|
|
if (OB_FAIL(handle_physical_plan(sql, context, result, pc_ctx, get_plan_err, true))) {
|
|
if (OB_ERR_PROXY_REROUTE == ret) {
|
|
LOG_DEBUG("fail to handle physical plan", K(ret));
|
|
} else {
|
|
LOG_WARN("fail to handle physical plan", K(ret));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && (OB_FAIL(after_get_plan(pc_ctx,
|
|
session,
|
|
result.get_physical_plan(),
|
|
result.get_is_from_plan_cache(),
|
|
&ps_params)))) {
|
|
LOG_WARN("fail to handle after get plan", K(ret));
|
|
}
|
|
}
|
|
} else if (stmt::T_ANONYMOUS_BLOCK == stmt_type && !context.is_pre_execute_) {
|
|
ParseResult parse_result;
|
|
MEMSET(&parse_result, 0, SIZEOF(ParseResult));
|
|
if (OB_FAIL(generate_physical_plan(parse_result, NULL, context, result,
|
|
false/*is_begin_commit_stmt*/, true))) {
|
|
LOG_WARN("generate physical plan failed", K(ret));
|
|
} else {
|
|
const ObPsSqlMeta &sql_meta = ps_info->get_ps_sql_meta();
|
|
const common::ObIArray<ObField> ¶m_fields = sql_meta.get_param_fields();
|
|
int64_t field_column_cnt = 0;
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < param_fields.count(); ++i) {
|
|
if (ObRoutineParamInOut::SP_PARAM_INOUT
|
|
== static_cast<ObRoutineParamInOut>(param_fields.at(i).inout_mode_)
|
|
|| ObRoutineParamInOut::SP_PARAM_OUT
|
|
== static_cast<ObRoutineParamInOut>(param_fields.at(i).inout_mode_)) {
|
|
field_column_cnt++;
|
|
}
|
|
}
|
|
OZ (result.reserve_field_columns(field_column_cnt));
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < field_column_cnt; ++i) {
|
|
ObField field;
|
|
field.type_.set_type(ObNullType);
|
|
OZ (result.add_field_column(field));
|
|
}
|
|
}
|
|
} else {
|
|
if (stmt::T_CALL_PROCEDURE == stmt_type && !context.is_dynamic_sql_) {
|
|
// call procedure stmt call always parse as dynamic sql
|
|
context.is_dynamic_sql_ = true;
|
|
}
|
|
ObParser parser(allocator, session.get_sql_mode(),
|
|
session.get_local_collation_connection());
|
|
ParseResult parse_result;
|
|
ParseMode parse_mode = context.is_dbms_sql_ ? DBMS_SQL_MODE :
|
|
context.is_dynamic_sql_ ? DYNAMIC_SQL_MODE :
|
|
(context.session_info_->is_for_trigger_package() ? TRIGGER_MODE : STD_MODE);
|
|
if (OB_FAIL(parser.parse(sql, parse_result, parse_mode))) {
|
|
LOG_WARN("failed to parse sql", K(ret), K(sql), K(stmt_type));
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(generate_physical_plan(
|
|
parse_result, NULL, context, result, false /*is_begin_commit_stmt*/, true))) {
|
|
LOG_WARN("generate physical plan failed", K(ret), K(sql), K(stmt_type));
|
|
} // TODO 生成物理计划的路径可x需q区分
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::handle_remote_query(const ObRemoteSqlInfo &remote_sql_info,
|
|
ObSqlCtx &context,
|
|
ObExecContext &exec_ctx,
|
|
ObCacheObjGuard& guard)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
//trim the sql first, let 'select c1 from t' and ' select c1 from t' and hit the same plan_cache
|
|
const ObString &trimed_stmt = remote_sql_info.remote_sql_;
|
|
|
|
ObIAllocator &allocator = THIS_WORKER.get_sql_arena_allocator();
|
|
ObSQLSessionInfo *session = exec_ctx.get_my_session();
|
|
exec_ctx.get_das_ctx().get_schema_guard() = context.schema_guard_;
|
|
int get_plan_err = OB_SUCCESS; //used for judge whether add plan to plan cache
|
|
bool is_from_plan_cache = false;
|
|
ObPlanCacheCtx *pc_ctx = NULL;
|
|
ParamStore param_store( (ObWrapperAllocator(allocator)) );
|
|
ObSEArray<ObString, 1> queries;
|
|
if (OB_ISNULL(session) || OB_ISNULL(remote_sql_info.ps_params_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("session is null", K(ret), K(session), K(remote_sql_info.ps_params_));
|
|
} else if (OB_ISNULL(pc_ctx =
|
|
static_cast<ObPlanCacheCtx *>(allocator.alloc(sizeof(ObPlanCacheCtx))))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("fail to alloc memory", K(ret), K(sizeof(ObPlanCacheCtx)));
|
|
} else {
|
|
#if !defined(NDEBUG)
|
|
LOG_INFO("Begin to handle remote statement",
|
|
K(remote_sql_info), "sess_id", session->get_sessid(),
|
|
"execution_id", session->get_current_execution_id());
|
|
#endif
|
|
const uint64_t tenant_id = session->get_effective_tenant_id();
|
|
bool use_plan_cache = session->get_local_ob_enable_plan_cache();
|
|
context.self_add_plan_ = false;
|
|
context.cur_sql_ = trimed_stmt;
|
|
pc_ctx = new (pc_ctx) ObPlanCacheCtx(trimed_stmt,
|
|
remote_sql_info.use_ps_, /*is_ps_mode*/
|
|
allocator,
|
|
context,
|
|
exec_ctx,
|
|
tenant_id);
|
|
pc_ctx->is_remote_executor_ = true;
|
|
if (remote_sql_info.use_ps_) {
|
|
//由于现在ps模式和普通的文本协议的执行计划不能复用,因此这里需要区分,避免在查询plan的时候引起一些问题
|
|
//由于普通的文本协议key_id是OB_INVALID_ID,因此这里使用key_id=0+name=参数化SQL的方式来区分
|
|
//@todo: shengle 普通的ps协议和文本协议的计划共享也存在同样的问题,这里需要统一解决一下
|
|
context.is_prepare_protocol_ = remote_sql_info.use_ps_;
|
|
context.spm_ctx_.bl_key_.db_id_ = session->get_database_id();
|
|
pc_ctx->fp_result_.pc_key_.key_id_ = 0;
|
|
pc_ctx->fp_result_.pc_key_.name_ = trimed_stmt;
|
|
pc_ctx->normal_parse_const_cnt_ = remote_sql_info.ps_params_->count();
|
|
pc_ctx->is_original_ps_mode_ = remote_sql_info.is_original_ps_mode_;
|
|
pc_ctx->set_is_ps_execute_stage();
|
|
if (OB_FAIL(construct_param_store(*remote_sql_info.ps_params_, param_store))) {
|
|
LOG_WARN("construct param store failed", K(ret));
|
|
} else if (OB_FAIL(construct_ps_param(param_store, *pc_ctx))) {
|
|
LOG_WARN("construct_ps_param failed", K(ret));
|
|
}
|
|
} else if (remote_sql_info.is_batched_stmt_) {
|
|
//这里保持跟控制端一致,如果是batched stmt,需要先做一次parser的切分
|
|
//切割出来的query最后走batched multi stmt的逻辑去查询plan cache和生成计划
|
|
ObParser parser(allocator,
|
|
session->get_sql_mode(),
|
|
session->get_local_collation_connection(),
|
|
pc_ctx->def_name_ctx_);
|
|
ObMPParseStat parse_stat;
|
|
if (OB_FAIL(parser.split_multiple_stmt(remote_sql_info.remote_sql_, queries, parse_stat))) {
|
|
LOG_WARN("split multiple stmt failed", K(ret), K(remote_sql_info));
|
|
} else {
|
|
context.multi_stmt_item_.set_batched_queries(&queries);
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
ObCacheObjGuard tmp_guard(MAX_HANDLE);
|
|
ObPhysicalPlan* plan = nullptr;
|
|
if (OB_FAIL(session->get_database_id(context.spm_ctx_.bl_key_.db_id_))) {
|
|
LOG_WARN("Failed to get database id", K(ret));
|
|
} else if (!use_plan_cache) {
|
|
if (context.multi_stmt_item_.is_batched_multi_stmt()) {
|
|
ret = OB_BATCHED_MULTI_STMT_ROLLBACK;
|
|
LOG_WARN("batched multi_stmt needs rollback");
|
|
}
|
|
} else if (OB_FAIL(pc_get_plan(*pc_ctx,
|
|
tmp_guard,
|
|
get_plan_err,
|
|
exec_ctx.get_need_disconnect_for_update()))) {
|
|
LOG_DEBUG("fail to get plan", K(ret));
|
|
} else if (FALSE_IT(plan = static_cast<ObPhysicalPlan*>(tmp_guard.get_cache_obj()))) {
|
|
// do nothing
|
|
} else if (OB_NOT_NULL(plan)) {
|
|
if (plan->is_local_plan()) {
|
|
is_from_plan_cache = true;
|
|
tmp_guard.init(pc_ctx->handle_id_);
|
|
guard.swap(tmp_guard);
|
|
} else {
|
|
//如果从plan cache中选择出来的plan不是local执行计划,说明不是remote sql想要的plan
|
|
//需要丢弃重新生成新的local plan
|
|
is_from_plan_cache = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret) && !is_from_plan_cache) { //没有从plan cache中拿到plan, 走长路径生成plan
|
|
//只需要plan,不需要其它信息,因此构造一个临时的result set
|
|
SMART_VAR(ObResultSet, tmp_result, *session, allocator) {
|
|
tmp_result.set_exec_context(exec_ctx);
|
|
//经过plan cache的计算后,param_store里的值可能会增加,因为plan cache中会执行pre calculation
|
|
//这里要再进行计划生成,需要把plan cache中pre calculation加入的param清除掉
|
|
int64_t initial_param_count = pc_ctx->fp_result_.ps_params_.count();
|
|
for (int64_t i = remote_sql_info.ps_params_->count(); i > initial_param_count; --i) {
|
|
remote_sql_info.ps_params_->pop_back();
|
|
}
|
|
if (OB_FAIL(handle_physical_plan(trimed_stmt, context, tmp_result, *pc_ctx, get_plan_err, remote_sql_info.use_ps_))) {
|
|
if (OB_ERR_PROXY_REROUTE == ret) {
|
|
LOG_DEBUG("fail to handle physical plan", K(ret));
|
|
} else {
|
|
LOG_WARN("fail to handle physical plan", K(ret));
|
|
}
|
|
} else {
|
|
// we need NOT to de some special operation for remote plan, this because we have swaped
|
|
// the life cycle of tmp_result's guard with remote_guard, which means plan's life becomes
|
|
// longer and we needn't to do other operation!!!
|
|
guard.swap(tmp_result.get_cache_obj_guard());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// set auto-increment related param into physical plan ctx
|
|
// if get plan from plan cache, reset its auto-increment variable here
|
|
// do not set variable for hidden primary key; its default value is 1
|
|
ObPhysicalPlan* plan = nullptr;
|
|
if (OB_SUCC(ret)) {
|
|
plan = static_cast<ObPhysicalPlan*>(guard.get_cache_obj());
|
|
if (OB_ISNULL(plan)) {
|
|
} else if (OB_UNLIKELY(!plan->is_local_plan())) {
|
|
//不是本地计划,控制端发送错误,返回错误码进行重试
|
|
ret = OB_LOCATION_NOT_EXIST;
|
|
LOG_WARN("plan type is invalid", K(remote_sql_info), KPC(plan));
|
|
} else if (OB_FAIL(after_get_plan(*pc_ctx,
|
|
*session,
|
|
plan,
|
|
is_from_plan_cache,
|
|
NULL /*ps param*/))) {
|
|
LOG_WARN("fail to handle after get plan", K(ret));
|
|
}
|
|
}
|
|
LOG_DEBUG("get remote plan", K(ret), K(is_from_plan_cache), KPC(plan));
|
|
//清空掉warning buffer,因为生成执行计划的warning buffer都在控制端记录下来,这里不需要再记录
|
|
//不然会导致warning消息重复
|
|
ob_reset_tsi_warning_buffer();
|
|
if (NULL != pc_ctx) {
|
|
pc_ctx->~ObPlanCacheCtx();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
template <typename ProcessorT>
|
|
int ObSql::handle_remote_batch_req(const ObReqTimestamp &req_ts, const char* buf, int32_t size)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
SMART_VAR(ProcessorT, processor, GCTX) {
|
|
processor.set_from_batch();
|
|
if (OB_FAIL(processor.init())) {
|
|
LOG_WARN("init processor failed", K(ret));
|
|
} else {
|
|
auto &arg = processor.get_arg();
|
|
int64_t pos = 0;
|
|
processor.set_receive_timestamp(req_ts.receive_timestamp_);
|
|
processor.set_run_timestamp(req_ts.run_timestamp_);
|
|
processor.set_enqueue_timestamp(req_ts.enqueue_timestamp_);
|
|
if (OB_FAIL(arg.deserialize(buf, size, pos))) {
|
|
LOG_WARN("deserialize processor arg failed", K(ret), K(size), K(pos));
|
|
} else if (OB_FAIL(processor.before_process())) {
|
|
LOG_WARN("before process failed", K(ret));
|
|
} else if (OB_FAIL(processor.process())) {
|
|
LOG_WARN("process remote batch req failed", K(ret));
|
|
} else if (OB_FAIL(processor.before_response(ret))) {
|
|
LOG_WARN("before response remote batch req failed", K(ret));
|
|
} else if (OB_FAIL(processor.after_process(ret))) {
|
|
LOG_WARN("after process batch req failed", K(ret));
|
|
}
|
|
}
|
|
processor.cleanup();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
OB_INLINE int ObSql::handle_text_query(const ObString &stmt, ObSqlCtx &context, ObResultSet &result)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
//trim the sql first, let 'select c1 from t' and ' select c1 from t' and hit the same plan_cache
|
|
ObString trimed_stmt = const_cast<ObString &>(stmt).trim();
|
|
context.is_prepare_protocol_ = false;
|
|
FLT_SET_TAG(sql_text, trimed_stmt);
|
|
char buf[4096];
|
|
STATIC_ASSERT(sizeof(ObPlanCacheCtx) < sizeof(buf), "ObPlanCacheCtx is too large");
|
|
if (OB_FAIL(init_result_set(context, result))) {
|
|
LOG_WARN("failed to init result set", K(ret));
|
|
} else if (trimed_stmt.empty()) {
|
|
ret = OB_ERR_EMPTY_QUERY;
|
|
LOG_WARN("query is empty", K(ret));
|
|
LOG_USER_ERROR(OB_ERR_EMPTY_QUERY);
|
|
// 空请求,可以归类到parser的已知错误,不需要断连接
|
|
result.get_exec_context().set_need_disconnect(false);
|
|
//FIXME qianfu NG_TRACE_EXT(set_need_disconnect, OB_ID(need_disconnect), false);
|
|
}
|
|
|
|
ObIAllocator &allocator = THIS_WORKER.get_sql_arena_allocator();
|
|
ObSQLSessionInfo &session = result.get_session();
|
|
const uint64_t tenant_id = session.get_effective_tenant_id();
|
|
ObExecContext& ectx = result.get_exec_context();
|
|
ectx.get_das_ctx().get_schema_guard() = context.schema_guard_;
|
|
int get_plan_err = OB_SUCCESS; //used for judge whether add plan to plan cache
|
|
bool use_plan_cache = session.get_local_ob_enable_plan_cache();
|
|
ObPlanCacheCtx *pc_ctx = NULL;
|
|
bool is_begin_commit_stmt = false;
|
|
if (OB_FAIL(ret)) {
|
|
// do nothing
|
|
//} else if (NULL == (pc_ctx = static_cast<ObPlanCacheCtx *>
|
|
// (allocator.alloc(sizeof(ObPlanCacheCtx))))) {
|
|
// ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
// LOG_WARN("fail to alloc memory", K(ret), K(sizeof(ObPlanCacheCtx)));
|
|
} else {
|
|
context.cur_sql_ = trimed_stmt;
|
|
pc_ctx = new (buf) ObPlanCacheCtx(trimed_stmt,
|
|
false, /*is_ps_mode*/
|
|
allocator,
|
|
context,
|
|
ectx,
|
|
tenant_id);
|
|
if (trimed_stmt.length() == 6) {
|
|
//是否为COMMIT语句
|
|
is_begin_commit_stmt = (0 == STRNCASECMP(trimed_stmt.ptr(), "commit", 6)
|
|
&& !context.multi_stmt_item_.is_batched_multi_stmt());
|
|
} else if (trimed_stmt.length() == 5) {
|
|
is_begin_commit_stmt = (0 == STRNCASECMP(trimed_stmt.ptr(), "begin", 5)
|
|
&& !context.multi_stmt_item_.is_batched_multi_stmt());
|
|
}
|
|
if (is_begin_commit_stmt) {
|
|
//记录当前语句是begin/commit 语句,用于性能优化
|
|
pc_ctx->set_begin_commit_stmt();
|
|
}
|
|
uint64_t database_id = OB_INVALID_ID;
|
|
|
|
if (OB_FAIL(session.get_database_id(database_id))) {
|
|
LOG_WARN("Failed to get database id", K(ret));
|
|
} else if (FALSE_IT(context.spm_ctx_.bl_key_.db_id_ =
|
|
(database_id == OB_INVALID_ID) ?
|
|
OB_OUTLINE_DEFAULT_DATABASE_ID:
|
|
database_id)) {
|
|
// do nothing
|
|
} else if (!use_plan_cache) {
|
|
if (context.multi_stmt_item_.is_batched_multi_stmt()) {
|
|
ret = OB_BATCHED_MULTI_STMT_ROLLBACK;
|
|
LOG_WARN("batched multi_stmt needs rollback");
|
|
}
|
|
// 如果是begin/commit语句,不再从plan cache中获取plan
|
|
} else if (!is_begin_commit_stmt
|
|
&& OB_FAIL(pc_get_plan_and_fill_result(*pc_ctx, result, get_plan_err,
|
|
ectx.get_need_disconnect_for_update()))) {
|
|
LOG_DEBUG("fail to get plan", K(ret));
|
|
}
|
|
}
|
|
|
|
int tmp_ret = ret;
|
|
if (!is_begin_commit_stmt && GCONF.enable_perf_event
|
|
&& OB_FAIL(handle_large_query(tmp_ret,
|
|
result,
|
|
ectx.get_need_disconnect_for_update(),
|
|
ectx))) {
|
|
//do nothing
|
|
}
|
|
if (OB_SUCC(ret) && !result.get_is_from_plan_cache()) { //没有从plan cache中拿到plan, 走长路径生成plan
|
|
if (OB_FAIL(handle_physical_plan(trimed_stmt, context, result, *pc_ctx, get_plan_err))) {
|
|
if (OB_ERR_PROXY_REROUTE == ret) {
|
|
LOG_DEBUG("fail to handle physical plan", K(ret));
|
|
} else {
|
|
LOG_WARN("fail to handle physical plan", K(ret));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// set auto-increment related param into physical plan ctx
|
|
// if get plan from plan cache, reset its auto-increment variable here
|
|
// do not set variable for hidden primary key; its default value is 1
|
|
if (OB_SUCC(ret)) {
|
|
if (!context.is_text_ps_mode_
|
|
&& OB_FAIL(after_get_plan(*pc_ctx, session, result.get_physical_plan(),
|
|
result.get_is_from_plan_cache(), NULL))) {
|
|
LOG_WARN("fail to handle after get plan", K(ret));
|
|
}
|
|
}
|
|
if (NULL != pc_ctx) {
|
|
pc_ctx->~ObPlanCacheCtx();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
OB_NOINLINE int ObSql::handle_large_query(int tmp_ret,
|
|
ObResultSet &result,
|
|
bool &need_disconnect,
|
|
ObExecContext &exec_ctx)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (tmp_ret != OB_SUCCESS
|
|
&& tmp_ret != OB_PC_LOCK_CONFLICT) {
|
|
ret = tmp_ret;
|
|
} else if (result.get_session().is_inner()
|
|
|| !ObStmt::is_dml_stmt(result.get_stmt_type())) {
|
|
ret = (tmp_ret == OB_PC_LOCK_CONFLICT) ? OB_SUCCESS : tmp_ret;
|
|
} else {
|
|
const int64_t curr_time = ObTimeUtility::current_time();
|
|
const int64_t lqt = GCONF.large_query_threshold;
|
|
int64_t elapsed_time = curr_time - THIS_THWORKER.get_query_start_time();
|
|
bool is_large_query = false;
|
|
bool lq_from_plan = true;
|
|
int64_t total_process_time = 0;
|
|
int64_t exec_times = 0;
|
|
ObPhysicalPlan *plan = NULL;
|
|
//用来自plan cache的plan预判是否为大请求
|
|
if (result.get_is_from_plan_cache()) {
|
|
if (OB_ISNULL(plan = result.get_physical_plan())) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(ret));
|
|
} else {
|
|
exec_times = plan->stat_.get_execute_count();
|
|
total_process_time = plan->stat_.total_process_time_;
|
|
if (exec_times > 0
|
|
&& (total_process_time / exec_times) > lqt) {
|
|
plan->inc_large_querys();
|
|
is_large_query = true;
|
|
lq_from_plan = true;
|
|
}
|
|
}
|
|
}
|
|
//实际编译时间判断是否为大请求
|
|
if (OB_SUCC(ret) && is_large_query == false) {
|
|
if (OB_PC_LOCK_CONFLICT == tmp_ret
|
|
|| elapsed_time > lqt) {
|
|
is_large_query = true;
|
|
lq_from_plan = false;
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && is_large_query && OB_FAIL(THIS_WORKER.check_large_query_quota())) {
|
|
need_disconnect = false;
|
|
if (lq_from_plan) {
|
|
plan->inc_delayed_large_querys();
|
|
LOG_INFO("It's a large query, need delay, do not need disconnect",
|
|
"avg_process_time", total_process_time / exec_times,
|
|
"exec_cnt", exec_times,
|
|
"large_query_threshold", lqt,
|
|
K(plan->get_plan_id()), K(ret));
|
|
} else {
|
|
LOG_INFO("compile time is too long, need delay", K(elapsed_time), K(ret));
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::generate_stmt(ParseResult &parse_result,
|
|
ObPlanCacheCtx *pc_ctx,
|
|
ObSqlCtx &context,
|
|
ObIAllocator &allocator,
|
|
ObResultSet &result,
|
|
ObStmt *&stmt,
|
|
ParseResult *outline_parse_result)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
FLTSpanGuard(resolve);
|
|
uint64_t session_id = 0;
|
|
ObResolverParams resolver_ctx;
|
|
ObPhysicalPlanCtx *plan_ctx = NULL;
|
|
ObSchemaChecker *schema_checker = NULL;
|
|
|
|
int64_t last_mem_usage = allocator.total();
|
|
int64_t resolver_mem_usage = 0;
|
|
if (OB_FAIL(sanity_check(context))) {
|
|
LOG_WARN("Failed to do sanity check", K(ret));
|
|
} else {
|
|
if (result.get_session().get_session_type() != ObSQLSessionInfo::INNER_SESSION) {
|
|
session_id = result.get_session().get_sessid_for_table();
|
|
} else {
|
|
session_id = OB_INVALID_ID; //内部session, 不受table_schema->session_id的可见性影响, 能看到查询建表过程中的表
|
|
}
|
|
schema_checker = OB_NEWx(ObSchemaChecker, (&allocator));
|
|
if (OB_UNLIKELY(NULL == schema_checker)) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_ERROR("Failed to malloc ObSchemaChecker", K(ret));
|
|
} else if (NULL == context.schema_guard_) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("context schema guard is null", K(ret));
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
resolver_ctx.allocator_ = &allocator;
|
|
resolver_ctx.schema_checker_ = schema_checker;
|
|
resolver_ctx.secondary_namespace_ = context.secondary_namespace_;
|
|
resolver_ctx.session_info_ = context.session_info_;
|
|
resolver_ctx.expr_factory_ = result.get_exec_context().get_expr_factory();
|
|
resolver_ctx.stmt_factory_ = result.get_exec_context().get_stmt_factory();
|
|
resolver_ctx.cur_sql_ = context.cur_sql_;
|
|
resolver_ctx.is_restore_ = context.is_restore_;
|
|
resolver_ctx.is_ddl_from_primary_ = context.is_ddl_from_primary_;
|
|
resolver_ctx.is_cursor_ = context.is_cursor_;
|
|
resolver_ctx.is_batch_stmt_ = context.multi_stmt_item_.is_batched_multi_stmt();
|
|
if (NULL != pc_ctx && pc_ctx->is_remote_executor_) {
|
|
resolver_ctx.need_check_col_dup_
|
|
= !(context.is_prepare_protocol_ && parse_result.question_mark_ctx_.by_ordinal_ && pc_ctx->is_original_ps_mode_);
|
|
} else {
|
|
resolver_ctx.need_check_col_dup_
|
|
= !(context.is_prepare_protocol_ && parse_result.question_mark_ctx_.by_ordinal_);
|
|
}
|
|
resolver_ctx.external_param_info_.by_name_
|
|
= parse_result.question_mark_ctx_.by_name_ || NULL != context.secondary_namespace_; //static sql in PL must be by name
|
|
resolver_ctx.outline_parse_result_ = outline_parse_result;
|
|
resolver_ctx.is_execute_call_stmt_ = context.is_execute_call_stmt_;
|
|
if (NULL != pc_ctx) {
|
|
resolver_ctx.select_item_param_infos_ = &pc_ctx->select_item_param_infos_;
|
|
}
|
|
plan_ctx = result.get_exec_context().get_physical_plan_ctx();
|
|
if (OB_ISNULL(plan_ctx) || OB_ISNULL(result.get_exec_context().get_stmt_factory())) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("Plan ctx should not be NULL", K(ret), KP(plan_ctx));
|
|
} else if (OB_ISNULL(resolver_ctx.query_ctx_ =
|
|
result.get_exec_context().get_stmt_factory()->get_query_ctx())) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_ERROR("allocate query context failed", K(ret));
|
|
} else {
|
|
resolver_ctx.query_ctx_->sql_schema_guard_.set_schema_guard(context.schema_guard_);
|
|
if (OB_FAIL(resolver_ctx.schema_checker_->init(resolver_ctx.query_ctx_->sql_schema_guard_, session_id))) {
|
|
LOG_WARN("init schema checker failed", K(ret));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
resolver_ctx.is_prepare_protocol_ = context.is_prepare_protocol_;
|
|
resolver_ctx.is_prepare_stage_ = context.is_prepare_stage_;
|
|
resolver_ctx.is_pre_execute_ = context.is_pre_execute_;
|
|
resolver_ctx.is_dynamic_sql_ = context.is_dynamic_sql_;
|
|
resolver_ctx.is_dbms_sql_ = context.is_dbms_sql_;
|
|
resolver_ctx.statement_id_ = context.statement_id_;
|
|
resolver_ctx.param_list_ = &plan_ctx->get_param_store();
|
|
resolver_ctx.sql_proxy_ = GCTX.sql_proxy_;
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (stmt::T_ANONYMOUS_BLOCK == context.stmt_type_ && context.is_prepare_protocol_ && !context.is_prepare_stage_) {
|
|
//anonymous + ps在execute阶段不会做parser, 因此不应该检查parser_result
|
|
//do nothing...
|
|
} else if (OB_ISNULL(parse_result.result_tree_)
|
|
|| OB_ISNULL(parse_result.result_tree_->children_)
|
|
|| OB_ISNULL(parse_result.result_tree_->children_[0])) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
SQL_LOG(WARN, "invalid args",
|
|
KP(parse_result.result_tree_),
|
|
KP(parse_result.result_tree_->children_),
|
|
KP(parse_result.result_tree_->children_[0]));
|
|
}
|
|
|
|
|
|
|
|
if (OB_SUCC(ret)) {
|
|
// set # of question marks
|
|
if (context.is_prepare_protocol_ && !context.is_prepare_stage_) {
|
|
resolver_ctx.query_ctx_->question_marks_count_ = plan_ctx->get_param_store().count();
|
|
LOG_DEBUG("question mark size is ", K(plan_ctx->get_param_store()));
|
|
} else {
|
|
resolver_ctx.query_ctx_->question_marks_count_ = static_cast<int64_t> (parse_result.question_mark_ctx_.count_);
|
|
LOG_DEBUG("question mark size is ", K(parse_result.question_mark_ctx_.count_));
|
|
}
|
|
|
|
ObResolver resolver(resolver_ctx);
|
|
NG_TRACE(resolve_begin);
|
|
if (stmt::T_ANONYMOUS_BLOCK == context.stmt_type_
|
|
&& context.is_prepare_protocol_
|
|
&& !context.is_prepare_stage_
|
|
&& !context.is_pre_execute_) {
|
|
ParseNode tmp_node;
|
|
tmp_node.type_ = T_SP_ANONYMOUS_BLOCK;
|
|
ret = resolver.resolve(ObResolver::IS_NOT_PREPARED_STMT, tmp_node, stmt);
|
|
} else {
|
|
ret = resolver.resolve(ObResolver::IS_NOT_PREPARED_STMT, *parse_result.result_tree_->children_[0], stmt);
|
|
ObItemType resolve_type = parse_result.result_tree_->children_[0]->type_;
|
|
switch (resolve_type) {
|
|
case T_CREATE_USER:
|
|
case T_SET_PASSWORD:
|
|
case T_GRANT:
|
|
case T_CREATE_ROLE:
|
|
case T_ALTER_ROLE:
|
|
case T_SET_ROLE_PASSWORD:
|
|
case T_SYSTEM_GRANT:
|
|
case T_GRANT_ROLE: {
|
|
context.is_sensitive_ = true;
|
|
break;
|
|
}
|
|
default: {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// set const param constraint after resolving
|
|
context.all_plan_const_param_constraints_ = &(resolver_ctx.query_ctx_->all_plan_const_param_constraints_);
|
|
context.all_possible_const_param_constraints_ = &(resolver_ctx.query_ctx_->all_possible_const_param_constraints_);
|
|
context.all_equal_param_constraints_ = &(resolver_ctx.query_ctx_->all_equal_param_constraints_);
|
|
context.all_pre_calc_constraints_ = &(resolver_ctx.query_ctx_->all_pre_calc_constraints_);
|
|
context.all_expr_constraints_ = &(resolver_ctx.query_ctx_->all_expr_constraints_);
|
|
context.cur_stmt_ = stmt;
|
|
|
|
LOG_DEBUG("got plan const param constraints", K(resolver_ctx.query_ctx_->all_plan_const_param_constraints_));
|
|
LOG_DEBUG("got all const param constraints", K(resolver_ctx.query_ctx_->all_possible_const_param_constraints_));
|
|
|
|
NG_TRACE(resolve_end);
|
|
//add ref obj schema version to PL and ps info
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(result.get_ref_objects().assign(resolver_ctx.query_ctx_->global_dependency_tables_))) {
|
|
LOG_WARN("assign ref obj schema version failed", K(ret));
|
|
}
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
/* for audit */
|
|
if (NULL != stmt) {
|
|
result.set_stmt_type(stmt->get_stmt_type());
|
|
}
|
|
SQL_LOG(WARN, "failed to resolve", K(ret));
|
|
} else {
|
|
// process stmt
|
|
if (NULL != stmt && NULL != resolver_ctx.query_ctx_) {
|
|
SQL_LOG(DEBUG, "SET STMT PARAM COUNT", K(resolver.get_params().prepare_param_count_), K(&resolver_ctx));
|
|
//secondary_namespace_不为空,说明是PL里sql的prepare阶段
|
|
//带有returning子句的动态sql也需要rebuild,用来去除into子句
|
|
//pl context not null indicate PL dynamic sql, only need rebuild PL dynamic sql
|
|
bool in_pl = NULL != resolver_ctx.secondary_namespace_
|
|
|| (resolver_ctx.is_dynamic_sql_ && OB_NOT_NULL(result.get_session().get_pl_context()))
|
|
|| resolver_ctx.is_dbms_sql_;
|
|
bool need_rebuild = lib::is_mysql_mode() ? false : resolver_ctx.is_prepare_stage_ && in_pl;
|
|
bool is_returning_into = false;
|
|
if (stmt->is_insert_stmt() || stmt->is_update_stmt() || stmt->is_delete_stmt()) {
|
|
ObDelUpdStmt &dml_stmt = static_cast<ObDelUpdStmt&>(*stmt);
|
|
if (dml_stmt.get_returning_into_exprs().count() != 0) {
|
|
need_rebuild = true;
|
|
is_returning_into = true;
|
|
}
|
|
}
|
|
if (need_rebuild) {
|
|
if (OB_FAIL(result.get_external_retrieve_info().build(*stmt,
|
|
result.get_session(),
|
|
resolver_ctx.secondary_namespace_,
|
|
resolver_ctx.is_dynamic_sql_ || resolver_ctx.is_dbms_sql_,
|
|
resolver.get_params().external_param_info_.params_))) {
|
|
SQL_LOG(WARN, "failed to build external retrieve info", K(ret));
|
|
} else {
|
|
if (result.get_external_params().empty() && result.get_into_exprs().empty()) {
|
|
if (resolver_ctx.query_ctx_->get_sql_stmt().empty()) {
|
|
resolver_ctx.query_ctx_->set_sql_stmt(parse_result.input_sql_, parse_result.input_sql_len_);
|
|
}
|
|
result.get_route_sql() = resolver_ctx.query_ctx_->get_sql_stmt();
|
|
resolver_ctx.query_ctx_->set_prepare_param_count(parse_result.question_mark_ctx_.count_);
|
|
} else if (is_returning_into && !in_pl) {
|
|
int64_t return_into_num = static_cast<ObDelUpdStmt&>(*stmt).get_returning_into_exprs().count();
|
|
resolver_ctx.query_ctx_->set_prepare_param_count(parse_result.question_mark_ctx_.count_- return_into_num);
|
|
} else {
|
|
// 对于oracle模式下pl内部的sql语句,到resolver完成后才能确定具体的prepare_param_count_
|
|
resolver_ctx.query_ctx_->set_prepare_param_count(resolver.get_params().prepare_param_count_);
|
|
}
|
|
}
|
|
} else {
|
|
if (stmt::T_ANONYMOUS_BLOCK == context.stmt_type_ && context.is_prepare_protocol_) {
|
|
resolver_ctx.query_ctx_->set_sql_stmt(context.cur_sql_);
|
|
} else {
|
|
resolver_ctx.query_ctx_->set_sql_stmt(parse_result.input_sql_, parse_result.input_sql_len_);
|
|
}
|
|
result.get_route_sql() = resolver_ctx.query_ctx_->get_sql_stmt();
|
|
resolver_ctx.query_ctx_->set_prepare_param_count(parse_result.question_mark_ctx_.count_);
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
result.set_stmt_type(stmt->get_stmt_type()); // used by query retry
|
|
result.set_literal_stmt_type(resolver_ctx.query_ctx_->get_literal_stmt_type()); // used by show warn, show trace
|
|
ObDMLStmt *dml_stmt = NULL;
|
|
ObVariableSetStmt *variable_set_stmt = NULL;
|
|
if ((dml_stmt = dynamic_cast<ObDMLStmt*>(stmt)) != NULL) {
|
|
const ObGlobalHint &global_hint = resolver_ctx.query_ctx_->get_global_hint();
|
|
result.set_is_calc_found_rows(dml_stmt->is_calc_found_rows());
|
|
plan_ctx->set_is_affect_found_row(dml_stmt->is_affect_found_rows());
|
|
context.force_print_trace_ = global_hint.force_trace_log_;
|
|
if (MpQuery == context.exec_type_ && global_hint.log_level_.length() > 0) {
|
|
const ObString &log_level = global_hint.log_level_;
|
|
if (OB_UNLIKELY(OB_SUCCESS != process_thread_log_id_level_map(log_level.ptr(),
|
|
log_level.length()))) {
|
|
LOG_WARN("Failed to process thread log id level map");
|
|
}
|
|
}
|
|
ObDelUpdStmt *del_up_stmt = NULL;
|
|
del_up_stmt = dynamic_cast<ObDelUpdStmt *>(dml_stmt);
|
|
if (del_up_stmt != NULL && del_up_stmt->is_returning()) {
|
|
result.set_returning(true);
|
|
}
|
|
} else if ((variable_set_stmt = dynamic_cast<ObVariableSetStmt*>(stmt)) != NULL) {
|
|
result.set_has_global_variable(variable_set_stmt->has_global_variable());
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
SQL_LOG(DEBUG, "Generate stmt success", K(*stmt));
|
|
} else {
|
|
LOG_WARN("failed to generate stmt", K(ret));
|
|
}
|
|
} else {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
SQL_LOG(WARN, "failed to generate stmt", K(ret));
|
|
}
|
|
}
|
|
}
|
|
resolver_mem_usage = allocator.total() - last_mem_usage;
|
|
LOG_DEBUG("SQL MEM USAGE", K(resolver_mem_usage), K(last_mem_usage));
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::generate_physical_plan(ParseResult &parse_result,
|
|
ObPlanCacheCtx *pc_ctx,
|
|
ObSqlCtx &sql_ctx,
|
|
ObResultSet &result,
|
|
const bool is_begin_commit_stmt,
|
|
const bool is_ps_mode /* false */,
|
|
ParseResult *outline_parse_result /* null */ )
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool is_valid = true;
|
|
ObStmt *basic_stmt = NULL;
|
|
ObIAllocator &allocator = result.get_mem_pool();
|
|
ObStmtNeedPrivs stmt_need_privs;
|
|
ObStmtOraNeedPrivs stmt_ora_need_privs;
|
|
const uint64_t tenant_id = result.get_session().get_effective_tenant_id();
|
|
stmt_need_privs.need_privs_.set_allocator(&allocator);
|
|
stmt_ora_need_privs.need_privs_.set_allocator(&allocator);
|
|
uint64_t aggregate_setting = 0;
|
|
// TODO: @linlin.xll remove ori_bl_key after eval_udf use identical sql ctx.
|
|
ObPlanBaseKeyGuard guard(sql_ctx.spm_ctx_.bl_key_);
|
|
_LOG_DEBUG("start to generate physical plan for query.(query = %.*s)",
|
|
parse_result.input_sql_len_, parse_result.input_sql_);
|
|
if (OB_FAIL(sanity_check(sql_ctx))) { //check sql_ctx.session_info_ and sql_ctx.schema_guard_
|
|
LOG_WARN("Failed to do sanity check", K(ret));
|
|
} else if (OB_FAIL(generate_stmt(parse_result,
|
|
pc_ctx,
|
|
sql_ctx,
|
|
allocator,
|
|
result,
|
|
basic_stmt,
|
|
outline_parse_result))) {
|
|
LOG_WARN("Failed to generate stmt", K(ret), K(result.get_exec_context().need_disconnect()));
|
|
} else if (OB_ISNULL(basic_stmt)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("Generate stmt success, but stmt is NULL", K(ret));
|
|
// begin/commit 语句不需要检查privilege
|
|
} else if (!is_begin_commit_stmt
|
|
&& OB_FAIL(ObPrivilegeCheck::check_privilege_new(sql_ctx,
|
|
basic_stmt,
|
|
stmt_need_privs,
|
|
stmt_ora_need_privs))) {
|
|
LOG_WARN("Failed to check ora privilege info", K(ret), K(*basic_stmt));
|
|
} else if (OB_FAIL(ObPrivilegeCheck::check_password_expired(sql_ctx,
|
|
basic_stmt->get_stmt_type()))) {
|
|
LOG_WARN("Falied to check password expired", K(ret));
|
|
} else if (sql_ctx.multi_stmt_item_.is_batched_multi_stmt() && NULL != pc_ctx &&
|
|
OB_FAIL(check_batched_multi_stmt_after_resolver(*pc_ctx,
|
|
*basic_stmt,
|
|
is_valid))) {
|
|
LOG_WARN("failed to check batched multi_stmt after resolver", K(ret));
|
|
} else if (!is_valid) {
|
|
ret = OB_BATCHED_MULTI_STMT_ROLLBACK;
|
|
LOG_WARN("batched multi_stmt needs rollback", K(ret));
|
|
} else { /*do nothing*/ }
|
|
|
|
if (OB_SUCC(ret)) {
|
|
if (basic_stmt->is_dml_stmt()
|
|
|| basic_stmt->is_explain_stmt()
|
|
|| basic_stmt->is_help_stmt()) {
|
|
ObPhysicalPlanCtx *pctx = result.get_exec_context().get_physical_plan_ctx();
|
|
bool allow_audit = false;
|
|
ObArray<ObAuditUnit> audit_units;
|
|
if (OB_ISNULL(pctx) || OB_ISNULL(result.get_exec_context().get_expr_factory())) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("Physical plan ctx should not be NULL", K(ret));
|
|
} else if (OB_ISNULL(result.get_exec_context().get_stmt_factory()->get_query_ctx())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("query ctx is null", K(ret));
|
|
} else if (OB_FAIL(fill_result_set(result, &sql_ctx, is_ps_mode, *basic_stmt))) {
|
|
LOG_WARN("Failed to fill result set", K(ret));
|
|
} else if (OB_FAIL(sql_ctx.session_info_->get_sys_variable(share::SYS_VAR__AGGREGATION_OPTIMIZATION_SETTINGS,
|
|
aggregate_setting))) {
|
|
LOG_WARN("failed to get aggregate setting", K(ret));
|
|
} else {
|
|
ObDMLStmt *stmt = static_cast<ObDMLStmt*>(basic_stmt);
|
|
SQL_LOG(DEBUG, "stmt", "stmt", *stmt);
|
|
SQL_LOG(DEBUG, "stmt success", "query", SJ(*stmt));
|
|
const ObGlobalHint &global_hint = stmt->get_query_ctx()->get_global_hint();
|
|
sql_ctx.session_info_->set_early_lock_release(global_hint.enable_lock_early_release_);
|
|
ObOptimizerContext optctx(sql_ctx.session_info_,
|
|
&result.get_exec_context(),
|
|
&result.get_exec_context().get_stmt_factory()->get_query_ctx()->sql_schema_guard_,
|
|
opt_stat_mgr_,
|
|
allocator,
|
|
&pctx->get_param_store(),
|
|
self_addr_,
|
|
GCTX.srv_rpc_proxy_,
|
|
global_hint,
|
|
*result.get_exec_context().get_expr_factory(),
|
|
stmt,
|
|
result.is_ps_protocol(),
|
|
result.get_exec_context().get_stmt_factory()->get_query_ctx());
|
|
optctx.set_aggregation_optimization_settings(aggregate_setting);
|
|
pctx->set_field_array(result.get_field_columns());
|
|
pctx->set_is_ps_protocol(result.is_ps_protocol());
|
|
bool is_restore = false;
|
|
uint64_t effective_tid = result.get_session().get_effective_tenant_id();
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_ISNULL(sql_ctx.schema_guard_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("schema guard is null", K(ret));
|
|
} else if (OB_FAIL(sql_ctx.schema_guard_->check_tenant_is_restore(
|
|
effective_tid, is_restore))) {
|
|
LOG_WARN("fail to check if tenant is restore", K(ret), K(effective_tid));
|
|
} else if (is_restore) {
|
|
// 为避免物理恢复阶段系统表恢复过程中,SQL依赖需要恢复的统计信息表,
|
|
// 对恢复中租户,仅需获取缺省统计信息即可
|
|
optctx.set_use_default_stat();
|
|
}
|
|
ObOptimizer optimizer(optctx);
|
|
bool use_jit = false;
|
|
bool turn_on_jit = sql_ctx.need_late_compile_;
|
|
// if (OB_FAIL(ret)) {
|
|
// } else if (OB_FAIL(need_use_jit(turn_on_jit,
|
|
// query_hint.use_jit_policy_,
|
|
// *sql_ctx.session_info_,
|
|
// use_jit))) {
|
|
// use_jit = false;
|
|
// LOG_WARN("failed to check for needing jitted expr", K(ret));
|
|
// } else {
|
|
// // do nothing
|
|
// }
|
|
|
|
ObLogPlan *logical_plan = NULL;
|
|
ObPhysicalPlan *phy_plan = NULL;
|
|
|
|
// 内部session切租户时资源处理分离不彻底
|
|
// 当用户请求发送到一个没有对应租户资源的server上时,plan 内存算在了普通租户上,
|
|
// 但是计划挂在了sys租户的plan cache下面,导致plan_cache_stat表数据统计异常,
|
|
// 出现疑似内存泄漏实际上却没有泄漏的情况。这里处理为直接从plan cache
|
|
// 中取tenant id,这样计划分配的资源就算在了plan cache所对应的租户上
|
|
if (OB_NOT_NULL(result.get_session().get_plan_cache())) {
|
|
effective_tid = result.get_session().get_plan_cache()->get_tenant_id();
|
|
}
|
|
|
|
ObCacheObjGuard& guard = result.get_cache_obj_guard();
|
|
guard.init(PLAN_GEN_HANDLE);
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(ObCacheObjectFactory::alloc(guard,
|
|
ObLibCacheNameSpace::NS_CRSR,
|
|
effective_tid))) {
|
|
LOG_WARN("fail to alloc phy_plan", K(ret));
|
|
} else if (FALSE_IT(phy_plan = static_cast<ObPhysicalPlan*>(guard.get_cache_obj()))) {
|
|
// do nothing
|
|
} else if (OB_UNLIKELY(NULL == phy_plan)) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_ERROR("Failed to alloc physical plan from tc factory", K(ret));
|
|
} else {
|
|
// update is_use_jit flag
|
|
phy_plan->stat_.is_use_jit_ = use_jit;
|
|
phy_plan->stat_.enable_early_lock_release_ = sql_ctx.session_info_->get_early_lock_release();
|
|
// if phy_plan's tenant id, which refers the tenant who create this plan,
|
|
// not equal to current effective_tid, plan cache must be invalid
|
|
// and we shouldn't add this plan to plan cache.
|
|
if (NULL != pc_ctx) {
|
|
pc_ctx->should_add_plan_ = (effective_tid==phy_plan->get_tenant_id());
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
phy_plan->set_fetch_cur_time(stmt->get_fetch_cur_time());
|
|
phy_plan->set_stmt_type(stmt->get_stmt_type());
|
|
phy_plan->set_literal_stmt_type(stmt->get_query_ctx()->get_literal_stmt_type());
|
|
if (phy_plan->get_fetch_cur_time() && !pctx->has_cur_time()) {
|
|
pctx->set_cur_time(ObTimeUtility::current_time(), *(sql_ctx.session_info_));
|
|
}
|
|
pctx->set_last_trace_id(sql_ctx.session_info_->get_last_trace_id());
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(transform_stmt(&stmt->get_query_ctx()->sql_schema_guard_,
|
|
opt_stat_mgr_,
|
|
&self_addr_,
|
|
phy_plan,
|
|
result.get_exec_context(),
|
|
stmt))) { //rewrite stmt
|
|
LOG_WARN("Failed to transform stmt", K(ret));
|
|
} else if (OB_FALSE_IT(optctx.set_root_stmt(stmt))) {
|
|
} else if (OB_FAIL(optimize_stmt(optimizer, *(sql_ctx.session_info_),
|
|
*stmt, logical_plan))) { //gen logical plan
|
|
LOG_WARN("Failed to optimizer stmt", K(ret));
|
|
} else if (OB_FAIL(create_expr_constraints(*stmt->get_query_ctx(),
|
|
result.get_exec_context()))){
|
|
LOG_WARN("Failed to create expr constraints", K(ret));
|
|
} else if (OB_ISNULL(logical_plan)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid null logical plan", K(ret), K(logical_plan));
|
|
} else if (OB_FAIL(code_generate(sql_ctx, result, stmt,
|
|
stmt_need_privs, stmt_ora_need_privs,
|
|
audit_units,
|
|
logical_plan, phy_plan))) { //gen phy plan
|
|
LOG_WARN("Failed to generate phy plan", K(ret));
|
|
}
|
|
|
|
// memory debug for sql work arena
|
|
if (OB_UNLIKELY(result.get_mem_pool().total() > SQL_MEM_SIZE_LIMIT)) {
|
|
int64_t total_mem_used = result.get_mem_pool().total();
|
|
LOG_INFO("[SQL MEM USAGE] use too much memory", K(total_mem_used),
|
|
K(ObString(parse_result.input_sql_len_, parse_result.input_sql_)));
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_ISNULL(stmt->get_query_ctx())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("query ctx is null", K(ret));
|
|
} else if (stmt::T_SELECT == stmt->get_stmt_type() &&
|
|
stmt::T_SHOW_PARAMETERS == stmt->get_query_ctx()->get_literal_stmt_type()) {
|
|
ObSelectStmt *select_stmt = static_cast<ObSelectStmt*>(stmt);
|
|
pctx->set_tenant_id(select_stmt->get_tenant_id());
|
|
pctx->set_show_seed(select_stmt->get_show_seed());
|
|
result.get_exec_context().reference_my_plan(phy_plan);
|
|
} else {
|
|
result.get_exec_context().reference_my_plan(phy_plan);
|
|
}
|
|
}
|
|
} else if (stmt::T_EXECUTE == basic_stmt->get_stmt_type()) {
|
|
if (OB_FAIL(handle_text_execute(basic_stmt, sql_ctx, result))) {
|
|
LOG_WARN("handle_text_execute failed", K(ret));
|
|
}
|
|
} else {
|
|
ObICmd *cmd = dynamic_cast<ObICmd*>(basic_stmt);
|
|
if (OB_UNLIKELY(NULL == cmd)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("fail cast basic stmt to cmd", K(ret));
|
|
} else {
|
|
result.set_cmd(cmd);
|
|
result.get_session().set_cur_sql_id(sql_ctx.sql_id_);
|
|
if (!is_begin_commit_stmt
|
|
&& OB_FAIL(fill_result_set(result, &sql_ctx, is_ps_mode, *basic_stmt))) {
|
|
LOG_WARN("Failed to fill result set", K(ret));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// execute dml in oracle mode, regardless of success or failure, always need to maintain object dependencies
|
|
if (OB_NOT_NULL(basic_stmt) && basic_stmt->is_dml_stmt()) {
|
|
int tmp_ret = ret;
|
|
ObDMLStmt *stmt = static_cast<ObDMLStmt*>(basic_stmt);
|
|
if (stmt->get_ref_obj_table()->is_inited()) {
|
|
if (OB_FAIL(stmt->get_ref_obj_table()->process_reference_obj_table(
|
|
tenant_id, sql_ctx, queue_))) {
|
|
LOG_WARN("failed to process reference obj table", K(ret));
|
|
} else {
|
|
// update the object's dependencies is successful, but may have failed when the plan
|
|
// was previously generated. need to return the previous error code
|
|
ret = tmp_ret;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// stmt 全量 const folding.
|
|
int ObSql::calc_pre_calculable_exprs(ObExecContext &exec_ctx,
|
|
ObDMLStmt &stmt,
|
|
ObPhysicalPlan &phy_plan)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_FAIL(calc_pre_calculable_exprs(stmt.get_calculable_exprs(),
|
|
exec_ctx,
|
|
stmt,
|
|
phy_plan))) {
|
|
LOG_WARN("Failed to calc pre cacluable exprs");
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// 为了改写层 const folding 抽出来的函数
|
|
int ObSql::calc_pre_calculable_exprs(
|
|
ObIArray<ObHiddenColumnItem> &calculable_exprs,
|
|
ObExecContext &exec_ctx,
|
|
ObDMLStmt &stmt,
|
|
ObPhysicalPlan &phy_plan)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
stmt::StmtType stmt_type = stmt::T_NONE;
|
|
ObDList <ObSqlExpression> pre_calc_exprs;
|
|
ObPhysicalPlanCtx *plan_ctx = exec_ctx.get_physical_plan_ctx();
|
|
ObSQLSessionInfo *session_info = exec_ctx.get_my_session();
|
|
ObRawExprFactory *expr_factory = exec_ctx.get_expr_factory();
|
|
if (OB_ISNULL(plan_ctx) || OB_ISNULL(session_info) || OB_ISNULL(expr_factory)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("NULL pointer", K(ret), KP(session_info), KP(expr_factory));
|
|
} else if (stmt.is_explain_stmt()) {
|
|
ObDMLStmt *real_stmt = static_cast<ObExplainStmt&>(stmt).get_explain_query_stmt();
|
|
if (OB_ISNULL(real_stmt)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("real_stmt is null", K(ret));
|
|
} else {
|
|
stmt_type = real_stmt->get_stmt_type();
|
|
}
|
|
} else {
|
|
stmt_type = stmt.get_stmt_type();
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < calculable_exprs.count(); i++) {
|
|
bool transformed = false;
|
|
if (OB_FAIL(ObTransformPreProcess::transform_expr(*expr_factory,
|
|
*session_info,
|
|
calculable_exprs.at(i).expr_,
|
|
transformed))) {
|
|
LOG_WARN("transform expr failed", K(ret));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
// is_ignore should be set before pre_calculate, which is used in column_conv
|
|
bool is_ignore_stmt = false;
|
|
bool need_fetch_cur_time = false;
|
|
ObDelUpdStmt *modify_stmt = dynamic_cast<ObDelUpdStmt*>(&stmt);
|
|
if (NULL != modify_stmt) {
|
|
is_ignore_stmt = modify_stmt->is_ignore();
|
|
}
|
|
|
|
if (OB_FAIL(calc_pre_calculable_exprs(stmt, calculable_exprs,
|
|
is_ignore_stmt, exec_ctx, phy_plan))) {
|
|
LOG_WARN("failed to generate and calcute rt exprs", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::transform_stmt(ObSqlSchemaGuard *sql_schema_guard,
|
|
common::ObOptStatManager *opt_stat_mgr,
|
|
common::ObAddr *self_addr,
|
|
ObPhysicalPlan *phy_plan,
|
|
ObExecContext &exec_ctx,
|
|
ObDMLStmt *&stmt)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
FLTSpanGuard(rewrite);
|
|
ObDMLStmt *transform_stmt = stmt;
|
|
int64_t last_mem_usage = exec_ctx.get_allocator().total();
|
|
int64_t transformer_mem_usage = 0;
|
|
//get transform stmt
|
|
if (OB_ISNULL(stmt) || OB_ISNULL(stmt->get_query_ctx()) || OB_ISNULL(sql_schema_guard) ||
|
|
OB_ISNULL(sql_schema_guard->get_schema_guard()) ||
|
|
OB_ISNULL(opt_stat_mgr) || OB_ISNULL(self_addr)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("null point", K(stmt), KP(sql_schema_guard),
|
|
K(opt_stat_mgr), K(self_addr), K(ret));
|
|
} else if (OB_ISNULL(exec_ctx.get_my_session())) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("session_info and schema manager in sql_ctx should not be NULL", K(ret));
|
|
} else if (stmt->is_explain_stmt()) {
|
|
if (OB_ISNULL(transform_stmt = static_cast<ObExplainStmt*>(stmt)->get_explain_query_stmt())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("Explain query stmt is NULL", K(ret));
|
|
}
|
|
} else { }//do nothing
|
|
|
|
ObTransformerCtx trans_ctx;
|
|
ObSchemaChecker schema_checker;
|
|
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(schema_checker.init(*sql_schema_guard))) {
|
|
LOG_WARN("fail to init schema_checker", K(ret));
|
|
} else {
|
|
trans_ctx.allocator_ = &exec_ctx.get_allocator();
|
|
trans_ctx.schema_checker_ = &schema_checker;
|
|
trans_ctx.session_info_ = exec_ctx.get_my_session();
|
|
trans_ctx.exec_ctx_ = &exec_ctx;
|
|
trans_ctx.expr_factory_ = exec_ctx.get_expr_factory();
|
|
trans_ctx.stmt_factory_ = exec_ctx.get_stmt_factory();
|
|
trans_ctx.opt_stat_mgr_ = opt_stat_mgr;
|
|
trans_ctx.sql_schema_guard_ = sql_schema_guard;
|
|
trans_ctx.self_addr_ = self_addr;
|
|
// trans_ctx.merged_version_ = merged_version;
|
|
|
|
trans_ctx.phy_plan_ = phy_plan;
|
|
}
|
|
|
|
NG_TRACE(transform_begin);
|
|
if (OB_SUCC(ret) && transform_stmt->is_valid_transform_stmt()) {
|
|
ObTransformerImpl transformer(&trans_ctx);
|
|
if (OB_FAIL(transformer.transform(transform_stmt))) {
|
|
LOG_WARN("failed to transform statement", K(ret));
|
|
} else if (stmt->is_explain_stmt()) {
|
|
static_cast<ObExplainStmt*>(stmt)->set_explain_query_stmt(transform_stmt);
|
|
} else {
|
|
bool or_expansion_happened = false;
|
|
if (OB_FAIL(transformer.get_cost_based_trans_happened(OR_EXPANSION,
|
|
or_expansion_happened))) {
|
|
LOG_WARN("failed to check whether or_expansion happened", K(ret));
|
|
} else if (or_expansion_happened) {
|
|
if (OB_ISNULL(exec_ctx.get_physical_plan_ctx())) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("get unexpected null", K(exec_ctx.get_physical_plan_ctx()),
|
|
K(ret));
|
|
} else {
|
|
exec_ctx.get_physical_plan_ctx()->set_or_expand_transformed(true);
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
stmt = transform_stmt;
|
|
}
|
|
}
|
|
}
|
|
|
|
transformer_mem_usage = exec_ctx.get_allocator().total() - last_mem_usage;
|
|
LOG_DEBUG("SQL MEM USAGE", K(transformer_mem_usage), K(last_mem_usage));
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::optimize_stmt(
|
|
ObOptimizer &optimizer,
|
|
const ObSQLSessionInfo &session_info,
|
|
ObDMLStmt &stmt,
|
|
ObLogPlan *&logical_plan)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
FLTSpanGuard(optimize);
|
|
logical_plan = NULL;
|
|
LOG_TRACE("stmt to generate plan", K(stmt));
|
|
NG_TRACE(optimize_begin);
|
|
if (OB_FAIL(optimizer.optimize(stmt, logical_plan))) {
|
|
LOG_WARN("Failed to optimize logical plan", K(ret));
|
|
// do nothing(plan will be destructed in result set)
|
|
} else if (OB_FAIL(optimizer.update_column_usage_infos())) {
|
|
LOG_WARN("failed to update column usage infos", K(ret));
|
|
} else {
|
|
LOG_TRACE("logical plan", KPC(logical_plan));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::code_generate(
|
|
ObSqlCtx &sql_ctx,
|
|
ObResultSet &result,
|
|
ObDMLStmt *stmt,
|
|
ObStmtNeedPrivs &stmt_need_privs,
|
|
ObStmtOraNeedPrivs &stmt_ora_need_privs,
|
|
ObIArray<ObAuditUnit> &audit_units,
|
|
ObLogPlan *logical_plan,
|
|
ObPhysicalPlan *&phy_plan)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
FLTSpanGuard(code_generate);
|
|
int64_t last_mem_usage = 0;
|
|
int64_t codegen_mem_usage = 0;
|
|
ObPhysicalPlanCtx *pctx = result.get_exec_context().get_physical_plan_ctx();
|
|
bool use_jit = false;
|
|
if (OB_ISNULL(stmt) || OB_ISNULL(logical_plan) || OB_ISNULL(stmt->get_query_ctx())
|
|
|| OB_ISNULL(phy_plan) || OB_ISNULL(sql_ctx.session_info_)
|
|
|| OB_ISNULL(pctx)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("Logical_plan or phy_plan is NULL", K(ret), K(stmt), K(logical_plan), K(phy_plan),
|
|
"session", sql_ctx.session_info_);
|
|
//} else if (OB_FAIL(need_use_jit(sql_ctx.need_late_compile_,
|
|
// (stmt->get_stmt_hint().get_query_hint()).use_jit_policy_,
|
|
// *sql_ctx.session_info_,
|
|
// use_jit))) {
|
|
// LOG_WARN("failed to check for needing jitted expr", K(ret));
|
|
} else {
|
|
ObCodeGenerator code_generator(use_jit,
|
|
result.get_exec_context().get_min_cluster_version(),
|
|
&(pctx->get_datum_param_store()));
|
|
phy_plan->set_is_packed(logical_plan->get_optimizer_context().is_packed());
|
|
if (OB_FAIL(code_generator.generate(*logical_plan, *phy_plan))) {
|
|
LOG_WARN("Failed to generate physical plan", KPC(logical_plan), K(ret));
|
|
} else {
|
|
//session上的ignore_stmt状态给CG使用,在CG结束后需要清空掉
|
|
sql_ctx.session_info_->set_ignore_stmt(false);
|
|
LOG_DEBUG("phy plan", K(*phy_plan));
|
|
phy_plan->stat_.is_use_jit_ = use_jit;
|
|
phy_plan->set_returning(stmt->is_returning());
|
|
phy_plan->set_has_link_table(stmt->has_link_table());
|
|
// set plan insert flag : insert into values(..); // value num is n (n >= 1);
|
|
if (stmt->is_insert_stmt()) {
|
|
ObInsertStmt *insert_stmt = static_cast<ObInsertStmt *>(stmt);
|
|
phy_plan->set_is_plain_insert(!insert_stmt->value_from_select()
|
|
&& !insert_stmt->is_insert_up()
|
|
&& insert_stmt->get_subquery_exprs().empty()
|
|
&& !insert_stmt->is_replace());
|
|
}
|
|
last_mem_usage = phy_plan->get_mem_size();
|
|
}
|
|
}
|
|
NG_TRACE(cg_end);
|
|
|
|
// set phy table location in task_exec_ctx, query_timeout in exec_context
|
|
if (OB_SUCC(ret)) {
|
|
ObPhyPlanHint phy_hint(logical_plan->get_optimizer_context().get_global_hint());
|
|
// set larger query_time for IS
|
|
if (stmt->get_query_ctx()->has_is_table_) {
|
|
int tmp_ret = OB_SUCCESS;
|
|
if (phy_hint.query_timeout_ <= 0) {
|
|
if (OB_SUCCESS != (tmp_ret = sql_ctx.session_info_->get_query_timeout(
|
|
phy_hint.query_timeout_))) {
|
|
LOG_WARN("failed to get sys variable value", K(tmp_ret));
|
|
}
|
|
}
|
|
phy_hint.query_timeout_ *= 10;
|
|
} else {}//do nothing
|
|
ObSEArray<ObTablePartitionInfo *, 3> tbl_part_infos;
|
|
phy_plan->set_phy_plan_hint(phy_hint);//remember in phy_plan
|
|
if (OB_FAIL(ret)) {
|
|
// do nothing
|
|
} else {
|
|
if (OB_FAIL(logical_plan->get_global_table_partition_info(tbl_part_infos))) {
|
|
LOG_WARN("get_global_table_partition_info fails", K(ret));
|
|
} else if (OB_FAIL(sql_ctx.set_partition_infos(
|
|
tbl_part_infos,
|
|
result.get_exec_context().get_allocator()))) {
|
|
LOG_WARN("Failed to set table location in sql ctx", K(ret));
|
|
} else {
|
|
ObDASCtx &das_ctx = DAS_CTX(result.get_exec_context());
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < tbl_part_infos.count(); i++) {
|
|
ObTableLocation &tl = tbl_part_infos.at(i)->get_table_location();
|
|
if (!tl.use_das()) {
|
|
const ObCandiTableLoc &candi_table_loc = tbl_part_infos.at(i)->get_phy_tbl_location_info();
|
|
if (OB_FAIL(das_ctx.add_candi_table_loc(tl.get_loc_meta(), candi_table_loc))) {
|
|
LOG_WARN("add candi table location failed", K(ret), K(tl.get_loc_meta()), K(candi_table_loc));
|
|
}
|
|
}
|
|
} // for end
|
|
}
|
|
}
|
|
// get tablet id and partition id for non partition tables
|
|
if (OB_SUCC(ret)) {
|
|
bool skip_non_partition_optimized = false;
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < tbl_part_infos.count(); i++) {
|
|
ObTableLocation &tl = tbl_part_infos.at(i)->get_table_location();
|
|
if (tl.is_partitioned() || is_virtual_table(tl.get_loc_meta().ref_table_id_)) {
|
|
skip_non_partition_optimized = true;
|
|
break;
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && !skip_non_partition_optimized) {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < tbl_part_infos.count(); i++) {
|
|
ObTableLocation &tl = tbl_part_infos.at(i)->get_table_location();
|
|
if (OB_FAIL(tl.calc_not_partitioned_table_ids(result.get_exec_context()))) {
|
|
LOG_WARN("failed to calc not partitioned table ids", K(ret));
|
|
} else {
|
|
tl.set_is_non_partition_optimized(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// set table location for phy_plan
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(phy_plan->set_table_locations(tbl_part_infos, *sql_ctx.schema_guard_))) {
|
|
LOG_WARN("fail to set table locations", K(ret));
|
|
}
|
|
LOG_DEBUG("physical plan certain table location", K(tbl_part_infos));
|
|
}
|
|
}
|
|
|
|
// set multi stmt info
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(sql_ctx.set_multi_stmt_rowkey_pos(logical_plan->get_multi_stmt_rowkey_pos(),
|
|
result.get_exec_context().get_allocator()))) {
|
|
LOG_WARN("failed to set multi stmt rowkey pos", K(ret));
|
|
} else {
|
|
LOG_DEBUG("succeed to set multi stmt rowkey pos", K(ret));
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
bool use_plan_cache = sql_ctx.session_info_->get_local_ob_enable_plan_cache();
|
|
ObPlanCache *plan_cache = NULL;
|
|
if (OB_UNLIKELY(NULL == (plan_cache = sql_ctx.session_info_->get_plan_cache()))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("Invalid plan cache", K(ret));
|
|
} else {
|
|
if (use_plan_cache) {
|
|
if (OB_FAIL(phy_plan->set_stmt_need_privs(stmt_need_privs))) {
|
|
LOG_WARN("Failed to deep copy", K(ret), K(stmt_need_privs));
|
|
} else if (OB_FAIL(phy_plan->set_stmt_ora_need_privs(stmt_ora_need_privs))) {
|
|
LOG_WARN("Failed to deep copy", K(ret), K(stmt_ora_need_privs));
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(phy_plan->init_operator_stats())) {
|
|
LOG_WARN("fail to init operator stats", K(ret));
|
|
} else {
|
|
codegen_mem_usage = phy_plan->get_mem_size() - last_mem_usage;
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(phy_plan->set_audit_units(audit_units))) {
|
|
LOG_WARN("Failed to set audit units", K(ret), K(audit_units));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
LOG_DEBUG("SQL MEM USAGE", K(codegen_mem_usage), K(last_mem_usage));
|
|
|
|
return ret;
|
|
}
|
|
|
|
inline int ObSql::sanity_check(ObSqlCtx &context)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (!inited_) {
|
|
LOG_WARN("ob sql not inited");
|
|
} else if (OB_UNLIKELY(NULL == context.session_info_)
|
|
|| OB_UNLIKELY(NULL == context.schema_guard_)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument",
|
|
K(ret),
|
|
"session info", context.session_info_,
|
|
"schema manager", context.schema_guard_);
|
|
} else {
|
|
// do nothing
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::init_result_set(ObSqlCtx &context, ObResultSet &result_set)
|
|
{
|
|
return init_exec_context(context, result_set.get_exec_context());
|
|
}
|
|
|
|
OB_INLINE int ObSql::init_exec_context(const ObSqlCtx &context, ObExecContext &exec_ctx)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObTaskExecutorCtx &task_exec_ctx = exec_ctx.get_task_exec_ctx();
|
|
task_exec_ctx.set_retry_times(context.retry_times_);
|
|
if (OB_FAIL(exec_ctx.create_physical_plan_ctx())) {
|
|
LOG_WARN("faile to create physical plan ctx", K(ret));
|
|
} else {
|
|
ObMemAttr mem_attr;
|
|
mem_attr.label_ = ObModIds::OB_SQL_EXEC_CONTEXT;
|
|
mem_attr.tenant_id_ = context.session_info_->get_effective_tenant_id();
|
|
mem_attr.ctx_id_ = ObCtxIds::EXECUTE_CTX_ID;
|
|
exec_ctx.set_my_session(context.session_info_);
|
|
exec_ctx.set_mem_attr(mem_attr);
|
|
exec_ctx.set_sql_ctx(const_cast<ObSqlCtx*>(&context));
|
|
if (OB_NOT_NULL(exec_ctx.get_physical_plan_ctx()) && OB_NOT_NULL(context.session_info_)) {
|
|
int64_t query_timeout = 0;
|
|
context.session_info_->get_query_timeout(query_timeout);
|
|
exec_ctx.get_physical_plan_ctx()->set_timeout_timestamp(
|
|
context.session_info_->get_query_start_time() + query_timeout);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
ObPlanCache* ObSql::get_plan_cache(uint64_t tenant_id, const ObPCMemPctConf &pc_mem_conf)
|
|
{
|
|
return plan_cache_manager_.get_or_create_plan_cache(tenant_id, pc_mem_conf);
|
|
}
|
|
|
|
ObPsCache* ObSql::get_ps_cache(const uint64_t tenant_id, const ObPCMemPctConf &pc_mem_conf)
|
|
{
|
|
return plan_cache_manager_.get_or_create_ps_cache(tenant_id, pc_mem_conf);
|
|
}
|
|
|
|
int ObSql::revert_plan_cache(uint64_t tenant_id)
|
|
{
|
|
return plan_cache_manager_.revert_plan_cache(tenant_id);
|
|
}
|
|
|
|
int ObSql::execute_get_plan(ObPlanCache &plan_cache,
|
|
ObPlanCacheCtx &pc_ctx,
|
|
ObCacheObjGuard& guard)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObIAllocator &allocator = pc_ctx.allocator_;
|
|
ObSQLSessionInfo *session = pc_ctx.sql_ctx_.session_info_;
|
|
ObPhysicalPlanCtx *pctx = pc_ctx.exec_ctx_.get_physical_plan_ctx();
|
|
if (OB_ISNULL(session) || OB_ISNULL(pctx)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("session is NULL", K(ret));
|
|
} else if (pc_ctx.is_ps_mode_) {
|
|
ObPsStmtId stmt_id = pc_ctx.fp_result_.pc_key_.key_id_;
|
|
guard.init(PS_EXEC_HANDLE);
|
|
if (OB_FAIL(plan_cache.get_ps_plan(guard, stmt_id, pc_ctx))) {
|
|
if (OB_SQL_PC_NOT_EXIST == ret || OB_PC_LOCK_CONFLICT == ret) {
|
|
// do nothing
|
|
} else {
|
|
LOG_WARN("fail to get ps physical plan", K(ret));
|
|
}
|
|
}
|
|
} else {
|
|
guard.init(CLI_QUERY_HANDLE);
|
|
if (OB_FAIL(plan_cache.get_plan(allocator, pc_ctx, guard))) {
|
|
if (OB_SQL_PC_NOT_EXIST == ret || OB_PC_LOCK_CONFLICT == ret) {
|
|
// do nothing
|
|
} else {
|
|
LOG_WARN("fail to get physical plan", K(ret));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::pc_get_plan_and_fill_result(ObPlanCacheCtx &pc_ctx,
|
|
ObResultSet &result,
|
|
int &get_plan_err,
|
|
bool &need_disconnect)
|
|
{
|
|
UNUSED(need_disconnect);
|
|
int ret = OB_SUCCESS;
|
|
ObPhysicalPlan *plan = NULL;
|
|
ObExecContext &exec_ctx = result.get_exec_context();
|
|
ObCacheObjGuard& guard = result.get_cache_obj_guard();
|
|
|
|
if (OB_FAIL(pc_get_plan(pc_ctx, guard, get_plan_err,
|
|
exec_ctx.get_need_disconnect_for_update()))) {
|
|
LOG_DEBUG("fail to get plan", K(ret));
|
|
} else if (OB_SUCCESS != get_plan_err) {
|
|
//get plan from plan cache failed
|
|
} else if ( FALSE_IT(plan = static_cast<ObPhysicalPlan*>(guard.get_cache_obj()))) {
|
|
// do nothing
|
|
} else if (OB_ISNULL(plan)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("plan is null", K(ret));
|
|
} else {
|
|
result.set_is_from_plan_cache(true);
|
|
// set handle after get physical plan
|
|
guard.init(pc_ctx.handle_id_);
|
|
if (OB_FAIL(result.from_plan(*plan, pc_ctx.fp_result_.raw_params_))) {
|
|
LOG_WARN("fail to set plan info to ResultSet", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::pc_get_plan(ObPlanCacheCtx &pc_ctx,
|
|
ObCacheObjGuard& guard,
|
|
int &get_plan_err,
|
|
bool &need_disconnect)
|
|
{
|
|
ObActiveSessionGuard::get_stat().in_get_plan_cache_ = true;
|
|
int ret = OB_SUCCESS;
|
|
//NG_TRACE(cache_get_plan_begin);
|
|
ObPlanCache *plan_cache = NULL;
|
|
ObSQLSessionInfo *session = pc_ctx.sql_ctx_.session_info_;
|
|
if (OB_ISNULL(session) || OB_ISNULL(plan_cache = session->get_plan_cache())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("Invalid plan cache", K(ret), K(session), K(plan_cache));
|
|
} else if (OB_FAIL(execute_get_plan(*plan_cache, pc_ctx, guard))) {
|
|
if (OB_EAGAIN == ret
|
|
|| OB_REACH_MAX_CONCURRENT_NUM == ret
|
|
|| OB_ARRAY_BINDING_ROLLBACK == ret
|
|
|| OB_ERR_PROXY_REROUTE == ret
|
|
|| OB_BATCHED_MULTI_STMT_ROLLBACK == ret) {
|
|
/*do nothing*/
|
|
} else if (!pc_ctx.is_ps_mode_
|
|
&& OB_PC_LOCK_CONFLICT == ret
|
|
&& !session->is_inner()) {
|
|
//不是ps模式, 不是inner sql, 且plan cache锁超时, 后面会放入大查询队列列,
|
|
//是ps模式或inner sql, 则不能丢队列, 走硬解析,
|
|
//ps暂不支持丢入大查询丢列, TODO shengle 后面单独添加,
|
|
//inner sql不能丢入大查询队列, 因为有可能上层查询已有数据返回客户端
|
|
} else {
|
|
get_plan_err = ret;
|
|
ret = OB_SUCCESS; //get plan出错, 覆盖错误码, 确保因plan cache的错误不影响正常执行路径
|
|
}
|
|
} else { //get plan 成功
|
|
plan_cache->inc_hit_and_access_cnt();
|
|
ObPhysicalPlan* plan = static_cast<ObPhysicalPlan*>(guard.get_cache_obj());
|
|
if (OB_ISNULL(plan)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("fail to get plan cache");
|
|
} else {
|
|
// 命中了plan cache,则不可能是commit或rollback语句,默认不断连接
|
|
need_disconnect = false;
|
|
//FIXME qianfu NG_TRACE_EXT(set_need_disconnect, OB_ID(need_disconnect), false);
|
|
pc_ctx.sql_ctx_.plan_cache_hit_ = true;
|
|
session->set_early_lock_release(plan->stat_.enable_early_lock_release_);
|
|
//极限性能场景下(perf_event=true),不再校验权限信息
|
|
if (!session->has_user_super_privilege() && !pc_ctx.sql_ctx_.is_remote_sql_ && GCONF.enable_perf_event) {
|
|
//we don't care about commit or rollback here because they will not cache in plan cache
|
|
if (ObStmt::is_write_stmt(plan->get_stmt_type(), false)
|
|
&& OB_FAIL(pc_ctx.sql_ctx_.schema_guard_->verify_read_only(
|
|
session->get_effective_tenant_id(),
|
|
plan->get_stmt_need_privs()))) {
|
|
LOG_WARN("database or table is read only, cannot execute this stmt");
|
|
}
|
|
}
|
|
//极限性能场景下(perf_event=true),不再校验权限信息
|
|
if (OB_SUCC(ret) && !pc_ctx.sql_ctx_.is_remote_sql_ && GCONF.enable_perf_event) {
|
|
//如果是remote sql第二次重入plan cache,不需要再做权限检查,因为在第一次进入plan cache已经检查过了
|
|
if (!ObSchemaChecker::is_ora_priv_check()) {
|
|
if (OB_FAIL(ObPrivilegeCheck::check_privilege(
|
|
pc_ctx.sql_ctx_,
|
|
plan->get_stmt_need_privs()))) {
|
|
LOG_WARN("No privilege", K(ret), "stmt_need_priv", plan->get_stmt_need_privs());
|
|
} else {
|
|
LOG_DEBUG("cached phy plan", K(*plan));
|
|
NG_TRACE(check_priv);
|
|
}
|
|
} else if (OB_FAIL(ObPrivilegeCheck::check_ora_privilege(
|
|
pc_ctx.sql_ctx_,
|
|
plan->get_stmt_ora_need_privs()))) {
|
|
LOG_WARN("No privilege", K(ret), "stmt_need_priv", plan->get_stmt_ora_need_privs());
|
|
} else {
|
|
LOG_DEBUG("cached phy plan", K(*plan));
|
|
NG_TRACE(check_priv);
|
|
}
|
|
if (OB_SUCC(ret) && OB_FAIL(ObPrivilegeCheck::check_password_expired(pc_ctx.sql_ctx_,
|
|
stmt::T_NONE))) {
|
|
LOG_WARN("Falied to check password expired", K(ret));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
FLT_SET_TAG(hit_plan, pc_ctx.sql_ctx_.plan_cache_hit_);
|
|
if (OB_ERR_PROXY_REROUTE == ret || OB_REACH_MAX_CONCURRENT_NUM == ret) {
|
|
// 如果sql需要二次路由,不应该断连接
|
|
need_disconnect = false;
|
|
}
|
|
ObActiveSessionGuard::get_stat().in_get_plan_cache_ = false;
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::get_outline_data(ObSqlCtx &context,
|
|
ObPlanCacheCtx &pc_ctx,
|
|
const ObString &signature_sql,
|
|
ObOutlineState &outline_state,
|
|
ParseResult &outline_parse_result)
|
|
{
|
|
NG_TRACE(transform_with_outline_begin);
|
|
int ret = OB_SUCCESS;
|
|
memset(&outline_parse_result, 0, sizeof(ParseResult));
|
|
ObString outline_content;
|
|
ObSQLSessionInfo *session = pc_ctx.sql_ctx_.session_info_;
|
|
if (OB_ISNULL(session)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get null session info", K(ret));
|
|
} else if (OB_FAIL(get_outline_data(pc_ctx, signature_sql, outline_state, outline_content))) {
|
|
LOG_WARN("failed to get outline data", K(ret));
|
|
}
|
|
|
|
if (OB_SUCC(ret) && !outline_content.empty()) {
|
|
ObParser parser(pc_ctx.allocator_, session->get_sql_mode(), session->get_local_collation_connection(), pc_ctx.def_name_ctx_);
|
|
ObSqlString sql_helper;
|
|
ObString temp_outline_sql;
|
|
if (OB_FAIL(sql_helper.assign_fmt("select %.*s 1 from dual", outline_content.length(),
|
|
outline_content.ptr()))) {
|
|
LOG_WARN("failed to temp outline data sql", K(outline_content), K(ret));
|
|
} else if (OB_FAIL(ob_write_string(pc_ctx.allocator_, sql_helper.string(), temp_outline_sql))) {
|
|
LOG_WARN("failed to write string", K(outline_content), K(ret));
|
|
} else if (OB_FAIL(parser.parse(temp_outline_sql, outline_parse_result))) {
|
|
{
|
|
LOG_WARN("failed to parse outline data result", K(ret), K(temp_outline_sql));
|
|
outline_state.reset();
|
|
ret = OB_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
NG_TRACE(transform_with_outline_end);
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::get_outline_data(ObPlanCacheCtx &pc_ctx,
|
|
const ObString &signature_sql,
|
|
ObOutlineState &outline_state,
|
|
ObString &outline_content)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const ObOutlineInfo *outline_info = NULL;
|
|
ObSchemaGetterGuard *schema_guard = pc_ctx.sql_ctx_.schema_guard_;
|
|
const uint64_t database_id = pc_ctx.sql_ctx_.spm_ctx_.bl_key_.db_id_;
|
|
const ObString sql_id = pc_ctx.sql_ctx_.spm_ctx_.bl_key_.sql_id_;
|
|
ObSQLSessionInfo *session = pc_ctx.sql_ctx_.session_info_;
|
|
outline_state.reset();
|
|
int64_t schema_version = OB_INVALID_VERSION;
|
|
if (OB_ISNULL(session) || OB_ISNULL(schema_guard)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(session), K(schema_guard));
|
|
} else if (OB_FAIL(schema_guard->get_schema_version(session->get_effective_tenant_id(), schema_version))) {
|
|
LOG_WARN("fail to get schema version", K(ret), K(session->get_effective_tenant_id()));
|
|
} else if (OB_CORE_SCHEMA_VERSION >= schema_version) {
|
|
// local schema is fall behind, do not use outline
|
|
} else {
|
|
char *buf = NULL;
|
|
int64_t pos = 0;
|
|
int64_t size = signature_sql.get_serialize_size();
|
|
ObString outline_key;
|
|
ObIAllocator &allocator = CURRENT_CONTEXT->get_arena_allocator();
|
|
if (0 == size) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("signature sql serialize size is 0", K(ret), K(signature_sql));
|
|
} else if (OB_ISNULL(buf = (char *)allocator.alloc(size))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_ERROR("fail to alloc mem", K(ret));
|
|
} else if (OB_FAIL(signature_sql.serialize(buf, size, pos))) {
|
|
LOG_WARN("fail to serialize key", K(ret));
|
|
} else if (OB_FALSE_IT(outline_key.assign_ptr(buf, static_cast<ObString::obstr_size_t>(pos)))) {
|
|
} else if (OB_FAIL(schema_guard->get_outline_info_with_signature(session->get_effective_tenant_id(),
|
|
database_id,
|
|
outline_key,
|
|
outline_info))) {
|
|
LOG_WARN("failed to get outline info", K(session->get_effective_tenant_id()),
|
|
K(signature_sql), K(ret));
|
|
ret = OB_SUCCESS;
|
|
} else if (NULL == outline_info &&
|
|
OB_FAIL(schema_guard->get_outline_info_with_sql_id(session->get_effective_tenant_id(),
|
|
database_id,
|
|
sql_id,
|
|
outline_info))) {
|
|
LOG_WARN("failed to get outline info", K(session->get_effective_tenant_id()), K(ret));
|
|
ret = OB_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
if (OB_SUCC(ret) && NULL != outline_info) {
|
|
ObString outline_content_copy = outline_info->get_outline_content_str();
|
|
if (OB_FAIL(ObSQLUtils::convert_sql_text_from_schema_for_resolve(pc_ctx.allocator_,
|
|
session->get_dtc_params(),
|
|
outline_content_copy))) {
|
|
//outline_content is stored using UTF8, if client sql is GBK, convert may failed
|
|
LOG_WARN("fail to convert sql text", K(ret));
|
|
outline_content = ObString::make_empty_string();
|
|
ret = OB_SUCCESS;
|
|
} else {
|
|
outline_content = outline_content_copy;
|
|
outline_state.is_plan_fixed_ = !outline_info->get_outline_content_str().empty();
|
|
outline_state.outline_version_.object_id_ = outline_info->get_outline_id();
|
|
outline_state.outline_version_.version_ = outline_info->get_schema_version();
|
|
outline_state.outline_version_.object_type_ = DEPENDENCY_OUTLINE;
|
|
if (outline_info->has_outline_params()) {
|
|
pc_ctx.exec_ctx_.set_outline_params_wrapper(&outline_info->get_outline_params_wrapper());
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::parser_and_check(const ObString &outlined_stmt,
|
|
ObExecContext &exec_ctx,
|
|
ObPlanCacheCtx &pc_ctx,
|
|
ParseResult &parse_result,
|
|
int get_plan_err,
|
|
bool &add_plan_to_pc,
|
|
bool &is_enable_transform_tree)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObIAllocator &allocator = pc_ctx.allocator_;
|
|
ObSQLSessionInfo *session = exec_ctx.get_my_session();
|
|
|
|
ObPhysicalPlanCtx *pctx = exec_ctx.get_physical_plan_ctx();
|
|
bool is_stack_overflow = false;
|
|
bool is_show_variables = false;
|
|
if (OB_ISNULL(session)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("session is null", K(ret));
|
|
} else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) {
|
|
LOG_WARN("failed to check stack overflow", K(ret), K(is_stack_overflow));
|
|
} else if (is_stack_overflow) {
|
|
ret = OB_SIZE_OVERFLOW;
|
|
LOG_WARN("too deep recursive", K(ret), K(is_stack_overflow));
|
|
} else if (OB_ISNULL(pctx)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(ret));
|
|
} else {
|
|
pctx->reset_datum_param_store();
|
|
pctx->get_param_store_for_update().reuse();
|
|
ObParser parser(allocator, session->get_sql_mode(), session->get_local_collation_connection(), pc_ctx.def_name_ctx_);
|
|
if (OB_FAIL(parser.parse(outlined_stmt, parse_result,
|
|
pc_ctx.is_rewrite_sql_ ? UDR_SQL_MODE : STD_MODE,
|
|
pc_ctx.sql_ctx_.handle_batched_multi_stmt()))) {
|
|
LOG_WARN("Generate syntax tree failed", K(outlined_stmt), K(ret));
|
|
} else if (pc_ctx.is_ps_mode_
|
|
&& OB_FAIL(construct_param_store_from_ps_param(pc_ctx, pctx->get_param_store_for_update()))) {
|
|
LOG_WARN("construct param store failed", K(ret));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
// parser返回成功
|
|
if (OB_ISNULL(parse_result.result_tree_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("parse result tree is NULL", K(ret));
|
|
} else if (OB_UNLIKELY(parse_result.result_tree_->num_child_ < 1)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("child count of parse result tree is less than 1",
|
|
K(ret), K(parse_result.result_tree_->num_child_));
|
|
} else if (OB_ISNULL(parse_result.result_tree_->children_[0])) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_ERROR("children_[0] ofparse result tree is NULL",
|
|
K(ret), K(parse_result.result_tree_->num_child_));
|
|
} else {
|
|
ObItemType parse_stmt_type = parse_result.result_tree_->children_[0]->type_;
|
|
if (T_COMMIT == parse_stmt_type || T_ROLLBACK == parse_stmt_type) {
|
|
// 是commit或者rollback语句,默认断连接
|
|
} else {
|
|
// 不是commit或者rollback语句,默认不断连接
|
|
exec_ctx.set_need_disconnect(false);
|
|
//FIXME qianfu NG_TRACE_EXT(set_need_disconnect, OB_ID(need_disconnect), false);
|
|
}
|
|
}
|
|
} else if (OB_LIKELY(OB_ERR_PARSE_SQL == ret
|
|
|| OB_ERR_EMPTY_QUERY == ret
|
|
|| OB_SIZE_OVERFLOW == ret
|
|
|| OB_ERR_ILLEGAL_NAME == ret
|
|
|| OB_ERR_STR_LITERAL_TOO_LONG == ret
|
|
|| OB_ERR_NOT_VALID_ROUTINE_NAME == ret
|
|
|| OB_ERR_CONSTRUCT_MUST_RETURN_SELF == ret
|
|
|| OB_ERR_ONLY_FUNC_CAN_PIPELINED == ret
|
|
|| OB_ERR_NO_ATTR_FOUND == ret
|
|
|| OB_ERR_NON_INT_LITERAL == ret)) {
|
|
// parser返回已知的错误码,不需要断掉与客户端的连接
|
|
exec_ctx.set_need_disconnect(false);
|
|
//FIXME qianfu NG_TRACE_EXT(set_need_disconnect, OB_ID(need_disconnect), false);
|
|
} else {
|
|
// parser返回未知的错误码,需要断掉与客户端的连接
|
|
LOG_WARN("parser error number is unexpected, need disconnect", K(ret));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_ISNULL(parse_result.result_tree_)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid args", K(ret), KP(parse_result.result_tree_));
|
|
} else if (OB_ISNULL(parse_result.result_tree_->children_)
|
|
|| OB_UNLIKELY(parse_result.result_tree_->num_child_ < 1)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid args", K(ret), KP(parse_result.result_tree_->children_),
|
|
"number of children", parse_result.result_tree_->num_child_);
|
|
} else {
|
|
ParseNode *children_node = parse_result.result_tree_->children_[0];
|
|
if (OB_ISNULL(children_node)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid args", K(ret), KP(children_node));
|
|
//除了普通的dml stmt,explain stmt中存在?也需要这里一起判断
|
|
} else if (!pc_ctx.is_ps_mode_ &&
|
|
(children_node->type_ == T_EXPLAIN || IS_DML_STMT(children_node->type_))
|
|
&& (children_node->value_ > 0)) {
|
|
ret = OB_ERR_PARSE_SQL;//children_node->value_ > 0,说明具有question_mark
|
|
const char *err_msg = "?";
|
|
int32_t str_len = static_cast<int32_t>(strlen(err_msg));
|
|
int32_t line_no = 1;
|
|
LOG_USER_ERROR(OB_ERR_PARSE_SQL, ob_errpkt_strerror(OB_ERR_PARSER_SYNTAX, false), str_len, err_msg, line_no);
|
|
LOG_WARN("the text query is invalid", K(outlined_stmt), K(children_node->value_), K(ret));
|
|
} else {
|
|
ObItemType type = children_node->type_;
|
|
//如果是非DML语句, 则不进入plan cache
|
|
ObPlanCache *plan_cache = NULL;
|
|
if (T_SHOW_VARIABLES == type) {
|
|
is_show_variables = true;
|
|
}
|
|
if (IS_DML_STMT(type) || is_show_variables) {
|
|
if (OB_UNLIKELY(NULL == (plan_cache = session->get_plan_cache()))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("Invalid plan cache", K(ret));
|
|
} else {
|
|
plan_cache->inc_access_cnt();
|
|
if (OB_SQL_PC_NOT_EXIST == get_plan_err) {
|
|
add_plan_to_pc = true;
|
|
} else {
|
|
add_plan_to_pc = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
const uint64_t tenant_id = session->get_effective_tenant_id();
|
|
ObSqlTraits &sql_traits = pc_ctx.sql_traits_;
|
|
sql_traits.is_readonly_stmt_ = ObSQLUtils::is_readonly_stmt(parse_result);
|
|
sql_traits.is_modify_tenant_stmt_
|
|
= ObSQLUtils::is_modify_tenant_stmt(parse_result);
|
|
sql_traits.is_cause_implicit_commit_
|
|
= ObSQLUtils::cause_implicit_commit(parse_result);
|
|
sql_traits.is_commit_stmt_ = ObSQLUtils::is_commit_stmt(parse_result);
|
|
sql_traits.stmt_type_ = ObSQLUtils::get_sql_item_type(parse_result);
|
|
|
|
bool read_only = false;
|
|
//租户级别的read only检查
|
|
if (session->is_inner() || (pc_ctx.is_begin_commit_stmt() && !GCONF.enable_perf_event)) {
|
|
// FIXME:
|
|
// schema拆分后,为了避免建租户时获取不到租户read only属性导致建租户失败,对于inner sql
|
|
// 暂时跳过read only检查。实际上,对于tenant space系统表,不应该检查read only属性。
|
|
} else if (OB_ISNULL(pc_ctx.sql_ctx_.schema_guard_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid argument", K(pc_ctx.sql_ctx_.schema_guard_));
|
|
} else if (OB_FAIL(pc_ctx.sql_ctx_.schema_guard_->get_tenant_read_only(tenant_id, read_only))) {
|
|
LOG_WARN("fail to get tenant read only attribute", K(ret), K(tenant_id));
|
|
} else if (OB_FAIL(session->check_read_only_privilege(read_only,
|
|
sql_traits))) {
|
|
LOG_WARN("failed to check read_only privilege", K(ret));
|
|
if (ObSQLUtils::is_end_trans_stmt(parse_result)) {
|
|
int et_ret = OB_SUCCESS;
|
|
// 是commit或者rollback语句检查read only权限失败,不断连接
|
|
exec_ctx.set_need_disconnect(false);
|
|
//FIXME qianfu NG_TRACE_EXT(set_need_disconnect, OB_ID(need_disconnect), false);
|
|
LOG_WARN("is commit or rollback stmt, but fail to check read_only privilege, "
|
|
"rollback", K(ret));
|
|
// 回滚事务
|
|
int64_t plan_timeout = 0;
|
|
if (OB_SUCCESS != (et_ret = session->get_query_timeout(plan_timeout))) {
|
|
LOG_ERROR("fail to get query timeout", K(ret), K(et_ret));
|
|
} else {
|
|
pctx->set_timeout_timestamp(session->get_query_start_time() + plan_timeout);
|
|
if (OB_SUCCESS != (et_ret = ObSqlTransControl::explicit_end_trans(
|
|
exec_ctx, true))) { // 这里是显式回滚事务,失败了是要断连接的
|
|
LOG_ERROR("fail explicit rollback trans", K(ret), K(et_ret));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OB_FAIL(ret)) {
|
|
// do nothing
|
|
} else if (!is_enable_transform_tree) {
|
|
//pc_ctx.fp_result_.pc_key_.name_
|
|
if (OB_FAIL(ob_write_string(allocator,
|
|
pc_ctx.raw_sql_,
|
|
pc_ctx.fp_result_.pc_key_.name_))) {
|
|
LOG_WARN("failed to deep copy string", K(pc_ctx.raw_sql_), K(ret));
|
|
} else if (OB_FAIL(ob_write_string(allocator,
|
|
pc_ctx.raw_sql_,
|
|
pc_ctx.sql_ctx_.spm_ctx_.bl_key_.constructed_sql_))) {
|
|
LOG_WARN("failed to deep copy string", K(pc_ctx.raw_sql_), K(ret));
|
|
}
|
|
} else {
|
|
//对于create outline限流语句,可能会带有问题。我们需要对?做特殊处理,
|
|
//所以也需要经过transform_systax_tree
|
|
bool flag = false;
|
|
if ((add_plan_to_pc && !is_show_variables)
|
|
|| ((T_CREATE_OUTLINE == parse_result.result_tree_->children_[0]->type_
|
|
|| T_ALTER_OUTLINE == parse_result.result_tree_->children_[0]->type_)
|
|
&& (INT64_MAX != parse_result.result_tree_->children_[0]->value_))) {
|
|
flag = true;
|
|
if (T_CREATE_OUTLINE == parse_result.result_tree_->children_[0]->type_) {
|
|
if (1 != parse_result.result_tree_->children_[0]->children_[2]->value_) {
|
|
flag = false;
|
|
}
|
|
}
|
|
} else if (pc_ctx.sql_ctx_.multi_stmt_item_.is_batched_multi_stmt()) {
|
|
if (T_EXPLAIN == parse_result.result_tree_->children_[0]->type_) {
|
|
flag = true;
|
|
}
|
|
}
|
|
if (flag) {
|
|
bool is_transform_outline = (T_CREATE_OUTLINE == parse_result.result_tree_->children_[0]->type_
|
|
|| T_ALTER_OUTLINE == parse_result.result_tree_->children_[0]->type_);
|
|
if (is_transform_outline) {
|
|
LOG_WARN("is_transform_outline", K(is_transform_outline));
|
|
}
|
|
if (OB_FAIL(ObSqlParameterization::parameterize_syntax_tree(allocator,
|
|
is_transform_outline,
|
|
pc_ctx,
|
|
parse_result.result_tree_,
|
|
pctx->get_param_store_for_update(),
|
|
session->get_local_collation_connection()))) {
|
|
if (is_transform_outline) {
|
|
LOG_WARN("fail to parameterize syntax tree", K(ret));
|
|
} else {
|
|
//如果是因为参数化出错, 则需要重新进行parser, 生成新的parser tree, 之前的parser tree可能部分已参数化,
|
|
//并标记该查询不进plan cache,且下次不需要进行参数化, 从而确保参数化时出错不影响正常执行。
|
|
pctx->reset_datum_param_store();
|
|
is_enable_transform_tree = false;
|
|
if (OB_FAIL(SMART_CALL(parser_and_check(outlined_stmt,
|
|
exec_ctx,
|
|
pc_ctx,
|
|
parse_result,
|
|
get_plan_err,
|
|
add_plan_to_pc,
|
|
is_enable_transform_tree)))) {
|
|
LOG_WARN("fail to parameterize syntax tree", K(ret));
|
|
}
|
|
add_plan_to_pc = false;
|
|
}
|
|
} else {
|
|
parse_result.question_mark_ctx_.count_ = static_cast<int> (pctx->get_param_store().count());
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::pc_add_plan(ObPlanCacheCtx &pc_ctx,
|
|
ObResultSet &result,
|
|
ObOutlineState &outline_state,
|
|
ObPlanCache *plan_cache,
|
|
bool& plan_added)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObPhysicalPlan *phy_plan = result.get_physical_plan();
|
|
pc_ctx.fp_result_.pc_key_.namespace_ = ObLibCacheNameSpace::NS_CRSR;
|
|
plan_added = false;
|
|
bool is_batch_exec = pc_ctx.sql_ctx_.multi_stmt_item_.is_batched_multi_stmt();
|
|
omt::ObTenantConfigGuard tenant_config(TENANT_CONF(MTL_ID()));
|
|
if (OB_ISNULL(phy_plan) || OB_ISNULL(plan_cache)) {
|
|
ret = OB_NOT_INIT;
|
|
LOG_WARN("Fail to generate plan", K(phy_plan), K(plan_cache));
|
|
} else if (!tenant_config.is_valid()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("tenant config is invalid", K(ret));
|
|
} else if (OB_USE_PLAN_CACHE_NONE == phy_plan->get_phy_plan_hint().plan_cache_policy_) {
|
|
LOG_DEBUG("Hint not use plan cache");
|
|
} else if (OB_FAIL(result.to_plan(pc_ctx.is_ps_mode_, phy_plan))) {
|
|
LOG_WARN("Failed copy field to plan", K(ret));
|
|
} else if (OB_FAIL(ob_write_string(phy_plan->get_allocator(),
|
|
pc_ctx.is_ps_mode_ ? pc_ctx.raw_sql_ :
|
|
pc_ctx.sql_ctx_.spm_ctx_.bl_key_.constructed_sql_,
|
|
phy_plan->stat_.constructed_sql_))) {
|
|
LOG_WARN("failed to ob write string", K(ret));
|
|
} else if (OB_FAIL(ob_write_string(phy_plan->get_allocator(),
|
|
pc_ctx.sql_ctx_.spm_ctx_.bl_key_.sql_id_,
|
|
phy_plan->stat_.sql_id_))) {
|
|
LOG_WARN("failed to ob write string", K(ret));
|
|
} else if (pc_ctx.is_rewrite_sql_ && OB_FAIL(phy_plan->set_rule_name(pc_ctx.rule_name_))) {
|
|
LOG_WARN("failed to ob write string", K(ret));
|
|
} else {
|
|
sql::ObUDRMgr *rule_mgr = MTL(sql::ObUDRMgr*);
|
|
phy_plan->set_outline_state(outline_state);
|
|
phy_plan->stat_.db_id_ = pc_ctx.sql_ctx_.spm_ctx_.bl_key_.db_id_;
|
|
phy_plan->stat_.is_rewrite_sql_ = pc_ctx.is_rewrite_sql_;
|
|
phy_plan->stat_.rule_version_ = rule_mgr->get_rule_version();
|
|
phy_plan->stat_.enable_udr_ = tenant_config->enable_user_defined_rewrite_rules;
|
|
|
|
if (pc_ctx.is_ps_mode_) {
|
|
//远程SQL第二次进入plan,将raw_sql作为pc_key存入plan cache中,
|
|
//然后使用ps接口直接用参数化后的sql作为key来查plan cache,可以节省一次对SQL fast parse的代价
|
|
if (pc_ctx.sql_ctx_.is_remote_sql_) {
|
|
//由于现在ps模式和普通的文本协议的执行计划不能复用,因此这里需要区分,避免在查询plan的时候引起一些问题
|
|
//由于普通的文本协议key_id是OB_INVALID_ID,因此这里使用key_id=0+name=参数化SQL的方式来区分
|
|
//@todo: shengle 普通的ps协议和文本协议的计划共享也存在同样的问题,这里需要统一解决一下
|
|
pc_ctx.fp_result_.pc_key_.key_id_ = 0;
|
|
pc_ctx.fp_result_.pc_key_.name_ = pc_ctx.raw_sql_;
|
|
}
|
|
ret = plan_cache->add_ps_plan(phy_plan, pc_ctx);
|
|
} else {
|
|
check_template_sql_can_be_prepare(pc_ctx, *phy_plan);
|
|
ret = plan_cache->add_plan(phy_plan, pc_ctx);
|
|
}
|
|
plan_added = (OB_SUCCESS == ret);
|
|
|
|
if (is_batch_exec) {
|
|
// 只有完整的插入了计划,才做batch优化执行,否则都认为需要回退成单行逐行执行
|
|
if (OB_FAIL(ret)) {
|
|
LOG_WARN("fail to add batch_execute_plan", K(ret));
|
|
ret = OB_BATCHED_MULTI_STMT_ROLLBACK;
|
|
} else {
|
|
pc_ctx.sql_ctx_.self_add_plan_ = true;
|
|
LOG_DEBUG("Successed to add batch plan to ObPlanCache", K(phy_plan));
|
|
}
|
|
} else if (OB_SQL_PC_PLAN_DUPLICATE == ret) {
|
|
ret = OB_SUCCESS;
|
|
LOG_DEBUG("this plan has been added by others, need not add again", K(phy_plan));
|
|
} else if (OB_REACH_MEMORY_LIMIT == ret || OB_SQL_PC_PLAN_SIZE_LIMIT == ret) {
|
|
if (REACH_TIME_INTERVAL(1000000)) { //1s, 当内存达到上限时, 该日志打印会比较频繁, 所以以1s为间隔打印
|
|
ObTruncatedString trunc_sql(pc_ctx.raw_sql_);
|
|
LOG_INFO("can't add plan to plan cache",
|
|
K(ret), K(phy_plan->get_mem_size()), K(trunc_sql),
|
|
K(plan_cache->get_mem_used()));
|
|
}
|
|
ret = OB_SUCCESS;
|
|
} else if (is_not_supported_err(ret)) {
|
|
ret = OB_SUCCESS;
|
|
LOG_DEBUG("plan cache don't support add this kind of plan now", K(phy_plan));
|
|
} else if (OB_FAIL(ret)) {
|
|
if (OB_REACH_MAX_CONCURRENT_NUM != ret) { //如果是达到限流上限, 则将错误码抛出去
|
|
ret = OB_SUCCESS; //add plan出错, 覆盖错误码, 确保因plan cache失败不影响正常执行路径
|
|
LOG_WARN("Failed to add plan to ObPlanCache", K(ret));
|
|
}
|
|
} else {
|
|
pc_ctx.sql_ctx_.self_add_plan_ = true;
|
|
LOG_DEBUG("Successed to add plan to ObPlanCache", K(phy_plan));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
//检查经过参数化的模板SQL能否被prepare
|
|
//目前有一些SQL如果走文本协议,plan cache参数化后的模板SQL并不能直接用来在远端prepare
|
|
//会报语法错误,例如:select * from t1 where a=_utf8'binary';
|
|
//模板化后的SQL为:select * from t1 where a=_utf8?;这条SQL在parser中会报语法错误
|
|
//而对于大多数参数化后的模板SQL可以直接用来在远端prepare,避免再对文本进行一次fast parser
|
|
//因此这里对模板SQL进行一次parser,增加对模板SQL的检查,用来判该模板SQL是否可以在远端被prepare
|
|
void ObSql::check_template_sql_can_be_prepare(ObPlanCacheCtx &pc_ctx, ObPhysicalPlan &plan)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const ObString &temp_sql = plan.get_constructed_sql();
|
|
ObSQLSessionInfo *session = pc_ctx.sql_ctx_.session_info_;
|
|
if (plan.is_remote_plan() && !temp_sql.empty() && session != nullptr
|
|
&& pc_ctx.select_item_param_infos_.empty()) {
|
|
// select * from (select 1, 2, 3 from dual);这样的SQL也不能在远端被prepare,因为select子句会被参数化
|
|
ParseResult parse_result;
|
|
ObParser parser(pc_ctx.allocator_,
|
|
session->get_sql_mode(),
|
|
session->get_local_collation_connection(),
|
|
pc_ctx.def_name_ctx_);
|
|
if (OB_FAIL(parser.parse(temp_sql, parse_result))) {
|
|
LOG_DEBUG("generate syntax tree failed", K(temp_sql), K(ret));
|
|
} else {
|
|
plan.set_temp_sql_can_prepare();
|
|
}
|
|
}
|
|
}
|
|
|
|
int ObSql::after_get_plan(ObPlanCacheCtx &pc_ctx,
|
|
ObSQLSessionInfo &session,
|
|
ObPhysicalPlan *phy_plan,
|
|
bool from_plan_cache,
|
|
const ParamStore *ps_params)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObPhysicalPlanCtx *pctx = pc_ctx.exec_ctx_.get_physical_plan_ctx();
|
|
bool enable_send_plan_event = EVENT_CALL(EventTable::EN_DISABLE_REMOTE_EXEC_WITH_PLAN) == 0;
|
|
bool evolution_plan = nullptr != phy_plan && phy_plan->get_evolution();
|
|
bool enable_send_plan = (session.get_is_in_retry() || evolution_plan) && enable_send_plan_event;
|
|
int last_query_retry_err = session.get_retry_info().get_last_query_retry_err();
|
|
if (OB_TRANSACTION_SET_VIOLATION == last_query_retry_err
|
|
|| OB_TRY_LOCK_ROW_CONFLICT == last_query_retry_err) {
|
|
enable_send_plan = false;
|
|
}
|
|
LOG_DEBUG("before after_get_plan", K(enable_send_plan), K(enable_send_plan_event),
|
|
"is_retry",session.get_is_in_retry(), K(last_query_retry_err), K(evolution_plan));
|
|
// LOG_INFO("after get paln", K(pctx), K(phy_plan));
|
|
if (NULL != pctx) {
|
|
if (NULL != phy_plan) {
|
|
// record the plan id in trace_event, perf_event and atomic_event
|
|
NG_TRACE_EXT(plan_id, OB_ID(plan_id), phy_plan->get_plan_id());
|
|
OB_ATOMIC_EVENT_SET_CAT_ID(phy_plan->get_plan_id());
|
|
PERF_SET_CAT_ID(phy_plan->get_plan_id());
|
|
if (OB_MAX_SQL_ID_LENGTH != phy_plan->stat_.sql_id_.length()) {
|
|
if (OB_FAIL(ob_write_string(phy_plan->get_allocator(),
|
|
pc_ctx.sql_ctx_.sql_id_,
|
|
phy_plan->stat_.sql_id_))) {
|
|
LOG_WARN("failed to ob write string", K(ret));
|
|
}
|
|
}
|
|
// init auto increment param
|
|
if (OB_FAIL(pc_ctx.exec_ctx_.init_physical_plan_ctx(*phy_plan))) {
|
|
LOG_WARN("fail init exec context", K(ret), K(phy_plan->get_stmt_type()));
|
|
} else if (OB_FAIL(DAS_CTX(pc_ctx.exec_ctx_).init(*phy_plan, pc_ctx.exec_ctx_))) {
|
|
LOG_WARN("init das context failed", K(ret));
|
|
} else if (OB_FAIL(pctx->set_autoinc_params(phy_plan->get_autoinc_params()))) {
|
|
LOG_WARN("failed to set autoinc params", K(ret));
|
|
} else {
|
|
pctx->set_tablet_autoinc_param(phy_plan->get_tablet_autoinc_param());
|
|
ObIArray<AutoincParam> &autoinc_params = pctx->get_autoinc_params();
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < autoinc_params.count(); ++i) {
|
|
AutoincParam ¶m = autoinc_params.at(i);
|
|
// Since 4.0, there should be only one autoinc_param
|
|
param.autoinc_increment_ = session.get_local_auto_increment_increment();
|
|
param.autoinc_offset_ = session.get_local_auto_increment_offset();
|
|
} // end for
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
DAS_CTX(pc_ctx.exec_ctx_).unmark_need_check_server();
|
|
bool need_reroute = false;
|
|
if (OB_FAIL(check_need_reroute(pc_ctx, phy_plan, need_reroute))) {
|
|
LOG_WARN("fail to check need reroute", K(ret));
|
|
} else if (need_reroute) {
|
|
ret = OB_ERR_PROXY_REROUTE;
|
|
}
|
|
}
|
|
|
|
// the purpose of adding condition (!session.get_is_in_retry()) is
|
|
// send the plan instead of continue sending sqlinfo when retrying remotely.
|
|
// bug: https://work.aone.alibaba-inc.com/issue/33487009
|
|
if (OB_SUCC(ret) && phy_plan->is_remote_plan()
|
|
&& !phy_plan->contains_temp_table()
|
|
&& !enable_send_plan) {
|
|
//处理远程plan转发SQL的情况
|
|
ParamStore ¶m_store = pctx->get_param_store_for_update();
|
|
if (OB_NOT_NULL(ps_params)) {
|
|
//本地是ps协议,远端依然走ps接口
|
|
int64_t initial_param_count = ps_params->count();
|
|
//对于ps协议为什么不使用用户传递下来的ps_params?因为对于Oracle模式下''等价于NULL
|
|
//这里需要做一次转换,而param store里的param是转换后的,因此不需要再去转换
|
|
for (int64_t i = param_store.count(); i > initial_param_count; --i) {
|
|
//丢掉计算产生的多余参数,只保留最初的参数,避免第二次生成计划的时候重复计算引起参数位置错误
|
|
param_store.pop_back();
|
|
}
|
|
pctx->get_remote_sql_info().use_ps_ = true;
|
|
pctx->get_remote_sql_info().is_original_ps_mode_ = true;
|
|
//从ps sql info中取出要执行的sql
|
|
pctx->get_remote_sql_info().remote_sql_ = pc_ctx.sql_ctx_.cur_sql_;
|
|
pctx->get_remote_sql_info().ps_params_ = ¶m_store;
|
|
pctx->get_remote_sql_info().ps_param_cnt_ = static_cast<int32_t>(param_store.count());
|
|
} else if (phy_plan->temp_sql_can_prepare()
|
|
&& pc_ctx.neg_param_index_.is_empty()
|
|
&& !pc_ctx.sql_ctx_.multi_stmt_item_.is_batched_multi_stmt()) {
|
|
//本地是文本协议的SQL,并且缓存在plan中,走ps协议
|
|
//@TODO:yuchen.wyc 文本协议中如果出现不能参数化的参数,由于param store里的值可能不是参数化对应的值
|
|
//例如select a, b-1 from t1; 这里会参数化成select a, b-? from t1;但param store里对应的是-1
|
|
//这里应该使用raw_params中的信息去解析并将param store中的-1替换成1
|
|
//但是处理太麻烦,暂时先不让这类SQL走远端的ps接口
|
|
//如果是batched_multi_stmt,也直接走文本协议,
|
|
//因为batched update stmt的参数在param store中是一个array,比较特殊
|
|
LOG_DEBUG("after get plan",
|
|
K(pc_ctx.fp_result_.raw_params_.count()),
|
|
K(pc_ctx.not_param_info_.count()),
|
|
K(param_store));
|
|
int64_t initial_param_count = pc_ctx.fp_result_.raw_params_.count() -
|
|
pc_ctx.not_param_index_.num_members();
|
|
for (int64_t i = param_store.count(); i > initial_param_count; --i) {
|
|
//丢掉计算产生的多余参数,只保留最初的参数,避免第二次生成计划的时候重复计算引起参数位置错误
|
|
param_store.pop_back();
|
|
}
|
|
pctx->get_remote_sql_info().use_ps_ = true;
|
|
pctx->get_remote_sql_info().remote_sql_ = phy_plan->get_constructed_sql();
|
|
pctx->get_remote_sql_info().ps_params_ = ¶m_store;
|
|
pctx->get_remote_sql_info().ps_param_cnt_ = static_cast<int32_t>(param_store.count());
|
|
} else {
|
|
//没有进plan cache,并且是文本协议,在远端再走一次文本解析
|
|
param_store.reset(); //走文本协议不需要携带参数,清空掉
|
|
pctx->get_remote_sql_info().use_ps_ = false;
|
|
pctx->get_remote_sql_info().is_batched_stmt_ =
|
|
pc_ctx.sql_ctx_.multi_stmt_item_.is_batched_multi_stmt();
|
|
pctx->get_remote_sql_info().remote_sql_ = pc_ctx.sql_ctx_.cur_sql_;
|
|
pctx->get_remote_sql_info().ps_params_ = ¶m_store;
|
|
}
|
|
LOG_DEBUG("generate remote sql info", K(pctx->get_remote_sql_info()),
|
|
K(session.get_local_ob_enable_plan_cache()),
|
|
K(pc_ctx.fp_result_.raw_params_), K(pc_ctx.not_param_info_),
|
|
K(phy_plan->temp_sql_can_prepare()),
|
|
K(pc_ctx.neg_param_index_),
|
|
K(pc_ctx.sql_ctx_.multi_stmt_item_.is_batched_multi_stmt()),
|
|
K(phy_plan->get_constructed_sql()), KPC(ps_params));
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
// set last_insert_id
|
|
pctx->set_last_insert_id_session(session.get_local_last_insert_id());
|
|
}
|
|
|
|
if (OB_SUCC(ret) && NULL != phy_plan) {
|
|
if (from_plan_cache) {
|
|
ObPhyPlanHint &phy_plan_hint = phy_plan->get_phy_plan_hint();
|
|
pc_ctx.sql_ctx_.force_print_trace_ = phy_plan_hint.force_trace_log_;
|
|
//log_level just deal mpquery now.
|
|
if (MpQuery == pc_ctx.sql_ctx_.exec_type_ && phy_plan_hint.log_level_.length() > 0) {
|
|
if (OB_FAIL(process_thread_log_id_level_map(phy_plan_hint.log_level_.ptr(),
|
|
phy_plan_hint.log_level_.length()))) {
|
|
LOG_WARN("Failed to process thread log id level map", K(ret));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && NULL != phy_plan && !session.get_is_deserialized()) {
|
|
if (phy_plan->is_contain_oracle_session_level_temporary_table()
|
|
|| phy_plan->contains_temp_table()) {
|
|
bool is_already_set = false;
|
|
if (OB_FAIL(session.get_session_temp_table_used(is_already_set))) {
|
|
LOG_WARN("fail to get session temp table used", K(ret));
|
|
} else if (is_already_set) {
|
|
//do nothing
|
|
} else if (OB_FAIL(session.set_session_temp_table_used(true))) {
|
|
LOG_WARN("fail to set session temp table used", K(ret));
|
|
}
|
|
LOG_DEBUG("plan contain oracle session level temporary table detected", K(is_already_set));
|
|
}
|
|
if (phy_plan->is_contain_oracle_trx_level_temporary_table()) {
|
|
bool is_already_set = session.has_tx_level_temp_table();
|
|
if (!is_already_set) {
|
|
session.set_tx_level_temp_table();
|
|
}
|
|
LOG_DEBUG("plan contain oracle trx level temporary table detected", K(is_already_set));
|
|
}
|
|
}
|
|
} else {
|
|
// not phy_plan, ignore
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::need_add_plan(const ObPlanCacheCtx &pc_ctx,
|
|
ObResultSet &result,
|
|
bool is_enable_pc,
|
|
bool &need_add_plan)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (false == need_add_plan) {
|
|
//do nothing
|
|
} else if (!is_enable_pc || !pc_ctx.should_add_plan_) {
|
|
need_add_plan = false;
|
|
} else if (OB_NOT_NULL(result.get_physical_plan()) &&
|
|
result.get_physical_plan()->has_link_table()) {
|
|
need_add_plan = false;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::pc_add_udr_plan(const ObUDRItemMgr::UDRItemRefGuard &item_guard,
|
|
ObPlanCacheCtx &pc_ctx,
|
|
ObResultSet &result,
|
|
ObOutlineState &outline_state,
|
|
bool& plan_added)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int get_plan_err = OB_SUCCESS;
|
|
bool add_plan_to_pc = false;
|
|
ParseResult parse_result;
|
|
ObIAllocator &allocator = result.get_mem_pool();
|
|
ObSQLSessionInfo &session = result.get_session();
|
|
ObPlanCache *plan_cache = session.get_plan_cache();
|
|
bool is_enable_transform_tree = !session.get_enable_exact_mode();
|
|
ObExecContext &ectx = result.get_exec_context();
|
|
ObPhysicalPlanCtx *pctx = ectx.get_physical_plan_ctx();
|
|
ParamStore param_store( (ObWrapperAllocator(&allocator)) );
|
|
const ObString &raw_sql = pc_ctx.raw_sql_;
|
|
ObPlanCacheCtx tmp_pc_ctx(raw_sql, pc_ctx.is_ps_mode_,
|
|
allocator, pc_ctx.sql_ctx_, ectx, session.get_effective_tenant_id());
|
|
tmp_pc_ctx.fp_result_ = pc_ctx.fp_result_;
|
|
tmp_pc_ctx.normal_parse_const_cnt_ = pc_ctx.normal_parse_const_cnt_;
|
|
tmp_pc_ctx.set_is_rewrite_sql(true);
|
|
tmp_pc_ctx.rule_name_ = pc_ctx.rule_name_;
|
|
const ObUDRItem *rule_item = item_guard.get_ref_obj();
|
|
ObParser parser(allocator, session.get_sql_mode(),
|
|
session.get_local_collation_connection(),
|
|
pc_ctx.def_name_ctx_);
|
|
if (OB_ISNULL(rule_item)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("rule item is null", K(ret));
|
|
} else if (OB_FAIL(tmp_pc_ctx.fixed_param_info_list_.assign(rule_item->get_fixed_param_value_array()))) {
|
|
LOG_WARN("failed to assign fixed param info list", K(ret));
|
|
} else if (OB_FAIL(tmp_pc_ctx.dynamic_param_info_list_.assign(rule_item->get_dynamic_param_info_array()))) {
|
|
LOG_WARN("failed to assign dynamic param info list", K(ret));
|
|
} else if (OB_FAIL(tmp_pc_ctx.tpl_sql_const_cons_.assign(pc_ctx.tpl_sql_const_cons_))) {
|
|
LOG_WARN("failed to assign tpl sql const cons", K(ret));
|
|
} else if (OB_FAIL(parser.parse(raw_sql, parse_result))) {
|
|
LOG_WARN("failed to parse sql", K(ret), K(raw_sql));
|
|
} else if (OB_FAIL(ObSqlParameterization::parameterize_syntax_tree(allocator,
|
|
false/*is_transform_outline*/,
|
|
tmp_pc_ctx,
|
|
parse_result.result_tree_,
|
|
param_store,
|
|
session.get_local_collation_connection()))) {
|
|
LOG_WARN("parameterize syntax tree failed", K(ret));
|
|
} else if (OB_FAIL(pc_add_plan(tmp_pc_ctx, result, outline_state, plan_cache, plan_added))) {
|
|
LOG_WARN("failed to add plan", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
OB_NOINLINE int ObSql::handle_physical_plan(const ObString &trimed_stmt,
|
|
ObSqlCtx &context,
|
|
ObResultSet &result,
|
|
ObPlanCacheCtx &pc_ctx,
|
|
const int get_plan_err,
|
|
bool is_psmode)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
FLTSpanGuard(hard_parse);
|
|
bool is_valid = true;
|
|
ObString outlined_stmt = trimed_stmt;//use outline if available
|
|
ObString signature_sql;
|
|
ObOutlineState outline_state;
|
|
ParseResult parse_result;
|
|
ParseResult outline_parse_result;
|
|
bool add_plan_to_pc = false;
|
|
bool is_match_udr = false;
|
|
ObUDRItemMgr::UDRItemRefGuard item_guard;
|
|
UDRBackupRecoveryGuard backup_recovery_guard(context, pc_ctx);
|
|
ObSQLSessionInfo &session = result.get_session();
|
|
ObPlanCache *plan_cache = session.get_plan_cache();
|
|
ObSpmCacheCtx &spm_ctx = context.spm_ctx_;
|
|
bool use_plan_cache = session.get_local_ob_enable_plan_cache();
|
|
// record whether needs to do parameterization at this time,
|
|
// if exact mode is on, not do parameterizaiton
|
|
bool is_enable_transform_tree = !session.get_enable_exact_mode();
|
|
//重新解析前将这两个标记reset掉,避免前面查plan cache的操作导致这两个参数在重新生成plan后会出现不幂等的问题
|
|
pc_ctx.not_param_index_.reset();
|
|
pc_ctx.neg_param_index_.reset();
|
|
bool plan_added = false;
|
|
bool need_get_baseline = false;
|
|
LOG_DEBUG("gen plan info", K(spm_ctx.bl_key_), K(get_plan_err));
|
|
// for batched multi stmt, we only parse and optimize the first statement
|
|
// only in multi_query, need do this
|
|
if (!is_psmode &&
|
|
context.multi_stmt_item_.is_batched_multi_stmt() &&
|
|
OB_FAIL(get_first_batched_multi_stmt(context.multi_stmt_item_, outlined_stmt))) {
|
|
LOG_WARN("failed to get first batched stmt item", K(ret));
|
|
} else if (OB_FAIL(ObUDRUtils::match_udr_and_refill_ctx(outlined_stmt,
|
|
context,
|
|
result,
|
|
pc_ctx,
|
|
is_match_udr,
|
|
item_guard))) {
|
|
LOG_WARN("failed to match udr and refill ctx", K(ret));
|
|
} else if (is_match_udr
|
|
&& FALSE_IT(outlined_stmt = item_guard.get_ref_obj()->get_replacement())) {
|
|
} else if (OB_FAIL(handle_parser(outlined_stmt,
|
|
result.get_exec_context(),
|
|
pc_ctx,
|
|
parse_result,
|
|
get_plan_err,
|
|
add_plan_to_pc,
|
|
is_enable_transform_tree))) {
|
|
LOG_WARN("fail to parser and check", K(ret));
|
|
} else if (context.multi_stmt_item_.is_batched_multi_stmt() &&
|
|
!is_psmode &&
|
|
OB_FAIL(check_batched_multi_stmt_after_parser(pc_ctx,
|
|
parse_result,
|
|
add_plan_to_pc,
|
|
is_valid))) {
|
|
LOG_WARN("failed to check batched multi_stmt", K(ret));
|
|
} else if (!is_valid) {
|
|
ret = OB_BATCHED_MULTI_STMT_ROLLBACK;
|
|
LOG_TRACE("batched multi_stmt needs rollback", K(ret));
|
|
}
|
|
generate_sql_id(pc_ctx, add_plan_to_pc, parse_result, signature_sql, ret);
|
|
if (OB_FAIL(ret)) {
|
|
// do nothing
|
|
} else if (OB_FAIL(get_outline_data(context, pc_ctx, signature_sql,
|
|
outline_state, outline_parse_result))) {
|
|
LOG_WARN("failed to get outline data for query", K(ret));
|
|
} else if (OB_FAIL(generate_physical_plan(parse_result,
|
|
&pc_ctx,
|
|
context,
|
|
result,
|
|
pc_ctx.is_begin_commit_stmt(),
|
|
is_psmode,
|
|
&outline_parse_result))) {
|
|
if (OB_ERR_PROXY_REROUTE == ret) {
|
|
LOG_DEBUG("Failed to generate plan", K(ret));
|
|
} else {
|
|
LOG_WARN("Failed to generate plan", K(ret), K(result.get_exec_context().need_disconnect()));
|
|
}
|
|
} else if (OB_FALSE_IT(backup_recovery_guard.recovery())) {
|
|
} else if (OB_FAIL(need_add_plan(pc_ctx,
|
|
result,
|
|
use_plan_cache,
|
|
add_plan_to_pc))) { //加入多表分布式计划的判断,判断是否还需需要add plan
|
|
LOG_WARN("get need_add_plan failed", K(ret));
|
|
} else if (!add_plan_to_pc) {
|
|
// do nothing
|
|
} else if (is_match_udr && OB_FAIL(pc_add_udr_plan(item_guard,
|
|
pc_ctx,
|
|
result,
|
|
outline_state,
|
|
plan_added))) {
|
|
LOG_WARN("fail to add plan to plan cache", K(ret));
|
|
} else if (!is_match_udr && OB_FAIL(pc_add_plan(pc_ctx, result, outline_state, plan_cache, plan_added))) {
|
|
LOG_WARN("fail to add plan to plan cache", K(ret));
|
|
}
|
|
//if the error code is ob_timeout, we add more error info msg for dml query.
|
|
if (OB_TIMEOUT == ret &&
|
|
parse_result.result_tree_ != NULL &&
|
|
parse_result.result_tree_->children_ != NULL &&
|
|
parse_result.result_tree_->num_child_ >= 1 &&
|
|
(parse_result.result_tree_->children_[0]->type_ == T_EXPLAIN ||
|
|
IS_DML_STMT(parse_result.result_tree_->children_[0]->type_) ||
|
|
IS_SHOW_STMT(parse_result.result_tree_->children_[0]->type_))) {
|
|
LOG_USER_ERROR(OB_TIMEOUT, THIS_WORKER.get_timeout_ts() - result.get_session().get_query_start_time());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::handle_parser(const ObString &sql,
|
|
ObExecContext &exec_ctx,
|
|
ObPlanCacheCtx &pc_ctx,
|
|
ParseResult &parse_result,
|
|
int get_plan_err,
|
|
bool &add_plan_to_pc,
|
|
bool &is_enable_transform_tree)
|
|
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
FLTSpanGuard(parse);
|
|
int64_t last_mem_usage = pc_ctx.allocator_.total();
|
|
int64_t parser_mem_usage = 0;
|
|
ObPhysicalPlanCtx *pctx = exec_ctx.get_physical_plan_ctx();
|
|
const ObSqlCtx *sql_ctx = exec_ctx.get_sql_ctx();
|
|
if (OB_ISNULL(pc_ctx.sql_ctx_.session_info_) || OB_ISNULL(pctx)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid argument", K(ret), KP(pctx), KP(pc_ctx.sql_ctx_.session_info_));
|
|
} else if (OB_FAIL(parser_and_check(sql, exec_ctx, pc_ctx, parse_result,
|
|
get_plan_err, add_plan_to_pc, is_enable_transform_tree))) {
|
|
LOG_WARN("fail to parser normal query", K(sql), K(ret));
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
pctx->set_original_param_cnt(pctx->get_param_store().count());
|
|
if (OB_FAIL(pctx->init_datum_param_store())) {
|
|
LOG_WARN("fail to init datum param store", K(ret));
|
|
}
|
|
}
|
|
LOG_DEBUG("SQL MEM USAGE", K(parser_mem_usage), K(last_mem_usage));
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::check_batched_multi_stmt_after_parser(ObPlanCacheCtx &pc_ctx,
|
|
ParseResult &parse_result,
|
|
bool add_plan_to_pc,
|
|
bool &is_valid)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
is_valid = false;
|
|
ObItemType type = parse_result.result_tree_->children_[0]->type_;
|
|
if (add_plan_to_pc
|
|
|| (ObSQLUtils::is_enable_explain_batched_multi_statement()
|
|
&& T_EXPLAIN == type)) {
|
|
is_valid = true;
|
|
// only update support batched multi-stmt optimization
|
|
if (OB_ISNULL(parse_result.result_tree_) ||
|
|
OB_ISNULL(parse_result.result_tree_->children_)) {
|
|
ret = OB_ERR_UNEXPECTED;;
|
|
LOG_WARN("get unexpected null", K(ret), KP(parse_result.result_tree_));
|
|
} else if (OB_UNLIKELY(parse_result.result_tree_->num_child_ < 1)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected child number", K(ret));
|
|
} else if (OB_ISNULL(parse_result.result_tree_->children_[0])) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (!(ObSQLUtils::is_support_batch_exec(type) || T_EXPLAIN == type)) {
|
|
is_valid = false;
|
|
} else { /*do nothing*/ }
|
|
|
|
if (OB_SUCC(ret) && is_valid && !pc_ctx.not_param_info_.empty()) {
|
|
if (OB_FAIL(ObPlanCacheValue::check_multi_stmt_not_param_value(pc_ctx.multi_stmt_fp_results_,
|
|
pc_ctx.not_param_info_,
|
|
is_valid))) {
|
|
LOG_WARN("failed to check multi stmt not param value", K(ret));
|
|
} else { /*do nothing*/ }
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::check_batched_multi_stmt_after_resolver(ObPlanCacheCtx &pc_ctx,
|
|
const ObStmt &stmt,
|
|
bool &is_valid)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObPhysicalPlanCtx *plan_ctx = NULL;
|
|
is_valid = true;
|
|
bool is_ps_ab_opt = pc_ctx.sql_ctx_.multi_stmt_item_.is_ab_batch_opt();
|
|
if (OB_ISNULL(plan_ctx = pc_ctx.exec_ctx_.get_physical_plan_ctx())
|
|
|| OB_ISNULL(pc_ctx.sql_ctx_.session_info_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (!(stmt.is_support_batch_exec_stmt() || stmt.is_explain_stmt())) {
|
|
is_valid = false;
|
|
} else {
|
|
const ObDelUpdStmt &delupd_stmt = stmt.is_explain_stmt()
|
|
? static_cast<const ObDelUpdStmt&>(*(static_cast<const ObExplainStmt&>(stmt).get_explain_query_stmt()))
|
|
: static_cast<const ObDelUpdStmt&>(stmt);
|
|
if (delupd_stmt.is_update_stmt() || delupd_stmt.is_delete_stmt()) {
|
|
if (1 != delupd_stmt.get_table_items().count() ||
|
|
!delupd_stmt.get_table_items().at(0)->is_basic_table()) {
|
|
is_valid = false;
|
|
}
|
|
}
|
|
if (delupd_stmt.has_order_by() || delupd_stmt.has_limit() ||
|
|
!delupd_stmt.get_returning_exprs().empty()) {
|
|
is_valid = false;
|
|
}
|
|
|
|
// make sure type of all the parameters are the same
|
|
if (OB_SUCC(ret) && is_valid) {
|
|
if (!is_ps_ab_opt) {
|
|
ParamStore *ab_params = NULL;
|
|
ObBitSet<> neg_param_index;
|
|
ObBitSet<> not_param_index;
|
|
ObBitSet<> must_be_positive_index;
|
|
int64_t query_num = pc_ctx.multi_stmt_fp_results_.count();
|
|
int64_t param_num = plan_ctx->get_param_store().count();
|
|
if (OB_ISNULL(ab_params = static_cast<ParamStore *>(pc_ctx.allocator_.alloc(sizeof(ParamStore))))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("failed to allocate memory", K(ret));
|
|
} else if (FALSE_IT(ab_params = new(ab_params)ParamStore(ObWrapperAllocator(pc_ctx.allocator_)))) {
|
|
// do nothing
|
|
} else if (OB_FAIL(ObSQLUtils::create_multi_stmt_param_store(pc_ctx.allocator_,
|
|
query_num,
|
|
param_num,
|
|
*ab_params))) {
|
|
LOG_WARN("failed to create multi_stmt param store", K(query_num), K(param_num),K(ret));
|
|
} else if (OB_FAIL(neg_param_index.add_members2(pc_ctx.neg_param_index_))) {
|
|
LOG_WARN("failed to assign bit sets", K(ret));
|
|
} else if (OB_FAIL(not_param_index.add_members2(pc_ctx.not_param_index_))) {
|
|
LOG_WARN("failed to assign bit sets", K(ret));
|
|
} else if (OB_FAIL(must_be_positive_index.add_members2(pc_ctx.must_be_positive_index_))) {
|
|
LOG_WARN("failed to assign bit sets", K(ret));
|
|
} else if (OB_FAIL(ObPlanCacheValue::check_multi_stmt_param_type(pc_ctx,
|
|
stmt.get_stmt_type(),
|
|
pc_ctx.param_charset_type_,
|
|
neg_param_index,
|
|
not_param_index,
|
|
must_be_positive_index,
|
|
*ab_params,
|
|
true,
|
|
is_valid))) {
|
|
LOG_WARN("failed to check multi-stmt param type", K(ret));
|
|
} else if (!is_valid) {
|
|
/*do nothing*/
|
|
} else {
|
|
pc_ctx.ab_params_ = ab_params;
|
|
ParamStore ¶m_store = plan_ctx->get_param_store_for_update();
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < param_store.count(); i++) {
|
|
ObObjParam &obj_param = param_store.at(i);
|
|
obj_param.get_param_flag().is_batch_parameter_ = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::replace_const_expr(ObIArray<ObRawExpr*> &raw_exprs,
|
|
ParamStore ¶m_store)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < raw_exprs.count(); i++) {
|
|
if (OB_FAIL(replace_const_expr(raw_exprs.at(i),
|
|
param_store))) {
|
|
LOG_WARN("failed to replace const expr", K(ret));
|
|
} else { /*do nothing*/ }
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::replace_const_expr(ObRawExpr *raw_expr,
|
|
ParamStore ¶m_store)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool is_stack_overflow = false;
|
|
if (OB_ISNULL(raw_expr)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret));
|
|
} else if (OB_FAIL(check_stack_overflow(is_stack_overflow))) {
|
|
LOG_WARN("check stack overflow failed", K(ret));
|
|
} else if (is_stack_overflow) {
|
|
ret = OB_SIZE_OVERFLOW;
|
|
LOG_WARN("too deep recursive", K(ret));
|
|
} else if (raw_expr->is_const_raw_expr()) {
|
|
ObConstRawExpr *const_expr = static_cast<ObConstRawExpr*>(raw_expr);
|
|
if (const_expr->get_value().is_unknown()) {
|
|
int pos = const_expr->get_value().get_unknown();
|
|
if (pos >= 0 && pos < param_store.count()) {
|
|
const_expr->set_param(param_store.at(pos));
|
|
} else { /*do nothing*/ }
|
|
}
|
|
} else {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < raw_expr->get_param_count(); i++) {
|
|
if (OB_FAIL(replace_const_expr(raw_expr->get_param_expr(i),
|
|
param_store))) {
|
|
LOG_WARN("failed to replace const expr", K(ret));
|
|
} else { /*do nothing*/ }
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void ObSql::generate_ps_sql_id(const ObString &raw_sql,
|
|
ObSqlCtx &context)
|
|
{
|
|
(void)ObSQLUtils::md5(raw_sql, context.sql_id_, (int32_t)sizeof(context.sql_id_));
|
|
}
|
|
|
|
void ObSql::generate_sql_id(ObPlanCacheCtx &pc_ctx,
|
|
bool add_plan_to_pc,
|
|
ParseResult &parse_result,
|
|
ObString &signature_sql,
|
|
int err_code)
|
|
{
|
|
// It has been checked during parser_and_check, there is no need to check again here
|
|
if (OB_SUCCESS == err_code
|
|
&& parse_result.result_tree_->children_[0]->type_ == T_SP_CALL_STMT) {
|
|
signature_sql = pc_ctx.sql_ctx_.spm_ctx_.bl_key_.constructed_sql_;
|
|
} else if (add_plan_to_pc == false
|
|
|| pc_ctx.is_ps_mode_
|
|
|| OB_SUCCESS != err_code) {
|
|
signature_sql = pc_ctx.raw_sql_;
|
|
} else {
|
|
signature_sql = pc_ctx.sql_ctx_.spm_ctx_.bl_key_.constructed_sql_;
|
|
}
|
|
(void)ObSQLUtils::md5(signature_sql,
|
|
pc_ctx.sql_ctx_.sql_id_,
|
|
(int32_t)sizeof(pc_ctx.sql_ctx_.sql_id_));
|
|
pc_ctx.sql_ctx_.spm_ctx_.bl_key_.sql_id_.assign_ptr(pc_ctx.sql_ctx_.sql_id_, strlen(pc_ctx.sql_ctx_.sql_id_));
|
|
}
|
|
|
|
|
|
int ObSql::calc_pre_calculable_exprs(const ObDMLStmt &stmt,
|
|
const ObIArray<ObHiddenColumnItem> &calculable_exprs,
|
|
const bool is_ignore_stmt,
|
|
ObExecContext &exec_ctx,
|
|
ObPhysicalPlan &phy_plan,
|
|
const uint64_t calc_types) /* default PRE_CALC_DEFAULT */
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
OB_ASSERT(NULL != exec_ctx.get_physical_plan_ctx() &&
|
|
NULL != exec_ctx.get_my_session() &&
|
|
NULL != exec_ctx.get_stmt_factory() &&
|
|
NULL != exec_ctx.get_stmt_factory()->get_query_ctx());
|
|
ObPhysicalPlanCtx *phy_plan_ctx = exec_ctx.get_physical_plan_ctx();
|
|
ObPreCalcExprFrameInfo *pre_calc_frame = NULL;
|
|
void *frame_buf = NULL;
|
|
bool need_fetch_cur_time = false;
|
|
if (OB_ISNULL(phy_plan_ctx)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("phy plan ctx is null", K(ret));
|
|
} else if (OB_ISNULL(frame_buf = phy_plan.get_allocator().alloc(
|
|
sizeof(ObPreCalcExprFrameInfo)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("failed to allocate memory", K(ret));
|
|
} else {
|
|
phy_plan_ctx->set_ignore_stmt(is_ignore_stmt);
|
|
DatumParamStore &datum_param_store = phy_plan_ctx->get_datum_param_store();
|
|
ObStaticEngineExprCG expr_cg(phy_plan.get_allocator(),
|
|
exec_ctx.get_my_session(),
|
|
exec_ctx.get_sql_ctx()->schema_guard_,
|
|
phy_plan_ctx->get_original_param_cnt(),
|
|
datum_param_store.count());
|
|
pre_calc_frame = new(frame_buf)ObPreCalcExprFrameInfo(phy_plan.get_allocator());
|
|
if (OB_FAIL(expr_cg.generate_calculable_exprs(calculable_exprs,
|
|
*pre_calc_frame))) {
|
|
LOG_WARN("failed to generate calculable exprs", K(ret));
|
|
} else {
|
|
phy_plan.set_fetch_cur_time(stmt.get_fetch_cur_time());
|
|
phy_plan.set_stmt_type(stmt.get_stmt_type());
|
|
phy_plan.set_literal_stmt_type(exec_ctx.get_stmt_factory()->get_query_ctx()->get_literal_stmt_type());
|
|
|
|
need_fetch_cur_time = phy_plan.get_fetch_cur_time() && !phy_plan_ctx->has_cur_time();
|
|
}
|
|
if (OB_FAIL(ret)) {
|
|
// set current time before do pre calculation
|
|
} else if (need_fetch_cur_time && FALSE_IT(phy_plan_ctx->set_cur_time(
|
|
ObTimeUtility::current_time(), *(exec_ctx.get_my_session())))) {
|
|
// do nothing
|
|
} else if (OB_FAIL(ObPlanCacheObject::pre_calculation(is_ignore_stmt,
|
|
*pre_calc_frame, exec_ctx,
|
|
calc_types))) {
|
|
LOG_WARN("failed to pre calculate exprs", K(ret));
|
|
} else if (OB_UNLIKELY(PRE_CALC_DEFAULT == calc_types &&
|
|
!phy_plan.get_pre_calc_frames().add_last(pre_calc_frame))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("failed to add list element", K(ret));
|
|
} else {
|
|
// do nothing
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::create_expr_constraints(ObQueryCtx &query_ctx, ObExecContext &exec_ctx)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObSEArray<ObHiddenColumnItem, 4> pre_calc_exprs;
|
|
ObHiddenColumnItem hidden_column_item;
|
|
int64_t idx = -1;
|
|
if (query_ctx.all_expr_constraints_.empty()) {
|
|
// do nothing
|
|
} else {
|
|
ObIArray<ObExprConstraint> &expr_constraints = query_ctx.all_expr_constraints_;
|
|
ObSEArray<ObHiddenColumnItem, 4> pre_calc_exprs;
|
|
ObHiddenColumnItem hidden_column_item;
|
|
int64_t idx = -1;
|
|
for (int64_t i = PRE_CALC_RESULT_NULL; OB_SUCC(ret) && i <= PRE_CALC_NOT_PRECISE; ++i) {
|
|
PreCalcExprExpectResult expect_result = static_cast<PreCalcExprExpectResult>(i);
|
|
pre_calc_exprs.reuse();
|
|
for (int64_t j = 0; OB_SUCC(ret) && j < expr_constraints.count(); ++j) {
|
|
if (expr_constraints.at(j).expect_result_ == expect_result) {
|
|
hidden_column_item.expr_ = expr_constraints.at(j).pre_calc_expr_;
|
|
hidden_column_item.hidden_idx_ = ++idx;
|
|
if (OB_FAIL(pre_calc_exprs.push_back(hidden_column_item))) {
|
|
LOG_WARN("failed to push back to array", K(ret));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && !pre_calc_exprs.empty()) {
|
|
if (OB_FAIL(create_expr_constraint(query_ctx,
|
|
exec_ctx,
|
|
pre_calc_exprs,
|
|
expect_result))) {
|
|
LOG_WARN("failed to create expr constraints for new engine", K(ret));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::create_expr_constraint(ObQueryCtx &query_ctx,
|
|
ObExecContext &exec_ctx,
|
|
const ObIArray<ObHiddenColumnItem> &pre_calc_exprs,
|
|
const PreCalcExprExpectResult expect_result)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ObPreCalcExprConstraint *pre_calc_constraint = NULL;
|
|
void *cons_buf = NULL;
|
|
ObPhysicalPlanCtx *plan_ctx = NULL;
|
|
if (OB_ISNULL(exec_ctx.get_sql_ctx()) || OB_ISNULL(plan_ctx = exec_ctx.get_physical_plan_ctx())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpect null", K(exec_ctx.get_sql_ctx()), K(plan_ctx), K(ret));
|
|
} else if (OB_ISNULL(cons_buf = exec_ctx.get_allocator().alloc(sizeof(ObPreCalcExprConstraint)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("failed to allocate memory", K(ret));
|
|
} else {
|
|
ObStaticEngineExprCG expr_cg(exec_ctx.get_allocator(), exec_ctx.get_my_session(),
|
|
exec_ctx.get_sql_ctx()->schema_guard_,
|
|
plan_ctx->get_original_param_cnt(),
|
|
plan_ctx->get_datum_param_store().count());
|
|
pre_calc_constraint = new(cons_buf)ObPreCalcExprConstraint(exec_ctx.get_allocator());
|
|
pre_calc_constraint->expect_result_ = expect_result;
|
|
if (OB_FAIL(expr_cg.generate_calculable_exprs(pre_calc_exprs,
|
|
pre_calc_constraint->pre_calc_expr_info_))) {
|
|
LOG_WARN("failed to generate calculable exprs", K(ret));
|
|
} else if (OB_UNLIKELY(!query_ctx.all_pre_calc_constraints_.add_last(pre_calc_constraint))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("failed to push back pre calc constraint", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// handle execute in text protocol
|
|
int ObSql::handle_text_execute(const ObStmt *basic_stmt,
|
|
ObSqlCtx &sql_ctx,
|
|
ObResultSet &result)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const ObExecuteStmt *exec_stmt = static_cast<const ObExecuteStmt*>(basic_stmt);
|
|
sql_ctx.is_text_ps_mode_ = true;
|
|
if (OB_ISNULL(exec_stmt)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("stmt is NULL", K(ret), KPC(exec_stmt), KPC(basic_stmt));
|
|
} else {
|
|
ObIAllocator &alloc = result.get_exec_context().get_allocator();
|
|
ObObjParam obj_param;
|
|
ParamStore param_store((ObWrapperAllocator(alloc)));
|
|
const ObRawExpr *raw_expr = NULL;
|
|
const ObIArray<const ObRawExpr*> &raw_expr_params = exec_stmt->get_params();
|
|
if (OB_FAIL(param_store.reserve(raw_expr_params.count()))) {
|
|
LOG_WARN("reserve param store failed", K(ret), K(raw_expr_params));
|
|
}
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < raw_expr_params.count(); ++i) {
|
|
if (OB_ISNULL(raw_expr = raw_expr_params.at(i))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("expr is NULL", K(ret), K(raw_expr_params));
|
|
} else if (OB_FAIL(ObSQLUtils::calc_const_expr(result.get_exec_context(),
|
|
raw_expr,
|
|
obj_param,
|
|
alloc,
|
|
param_store))) {
|
|
LOG_WARN("calc const expr failed", K(ret), KPC(exec_stmt));
|
|
} else {
|
|
obj_param.set_accuracy(raw_expr->get_accuracy());
|
|
obj_param.set_result_flag(raw_expr->get_result_flag());
|
|
obj_param.set_collation_level(CS_LEVEL_COERCIBLE);
|
|
if (OB_FAIL(param_store.push_back(obj_param))) {
|
|
LOG_WARN("push back into param_store failed", K(ret));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(handle_ps_execute(exec_stmt->get_prepare_id(),
|
|
exec_stmt->get_prepare_type(),
|
|
param_store,
|
|
sql_ctx,
|
|
result,
|
|
false/*is_inner_sql*/))) {
|
|
LOG_WARN("ps execute failed", K(ret));
|
|
}
|
|
}
|
|
LOG_DEBUG("handle text execute done", K(ret), KPC(exec_stmt), K(param_store));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::check_need_reroute(ObPlanCacheCtx &pc_ctx, ObPhysicalPlan *plan, bool &need_reroute)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
need_reroute = false;
|
|
ObDASCtx &das_ctx = pc_ctx.exec_ctx_.get_das_ctx();
|
|
if (OB_NOT_NULL(plan)
|
|
&& pc_ctx.sql_ctx_.can_reroute_sql_
|
|
&& (OB_PHY_PLAN_REMOTE == plan->get_plan_type()
|
|
|| (!das_ctx.is_partition_hit() && !das_ctx.get_table_loc_list().empty()))) {
|
|
// reroute request,
|
|
// physical table location is already calculated and stored in task_exec_ctx.table_locations_
|
|
bool should_reroute = true;
|
|
const DependenyTableStore &dep_tables = plan->get_dependency_table();
|
|
for (int64_t i = 0;
|
|
should_reroute && i < dep_tables.count();
|
|
i++) {
|
|
const ObSchemaObjVersion &schema_obj = dep_tables.at(i);
|
|
if (TABLE_SCHEMA == schema_obj.get_schema_type()
|
|
&& is_virtual_table(schema_obj.object_id_)) {
|
|
should_reroute = false;
|
|
}
|
|
}
|
|
if (OB_ISNULL(pc_ctx.sql_ctx_.schema_guard_)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid null schema guard", K(ret));
|
|
} else if (should_reroute) {
|
|
if (DAS_CTX(pc_ctx.exec_ctx_).get_table_loc_list().empty()) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null phy table location", K(ret));
|
|
} else {
|
|
const ObTableSchema *table_schema = NULL;
|
|
ObDASTableLoc *first_table_loc = DAS_CTX(pc_ctx.exec_ctx_).get_table_loc_list().get_first();
|
|
ObDASTabletLoc *first_tablet_loc = first_table_loc->get_first_tablet_loc();
|
|
ObLSReplicaLocation ls_replica_loc;
|
|
ObDASLocationRouter &loc_router = DAS_CTX(pc_ctx.exec_ctx_).get_location_router();
|
|
if (OB_FAIL(pc_ctx.sql_ctx_.schema_guard_->get_table_schema(
|
|
MTL_ID(),
|
|
first_table_loc->loc_meta_->ref_table_id_, table_schema))) {
|
|
LOG_WARN("failed to get table schema", K(ret));
|
|
} else if (OB_ISNULL(table_schema)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid null table schema", K(ret));
|
|
} else if (OB_ISNULL(pc_ctx.sql_ctx_.get_reroute_info())) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("get reroute info failed", K(ret));
|
|
} else if (OB_FAIL(loc_router.get_full_ls_replica_loc(table_schema->get_tenant_id(),
|
|
*first_tablet_loc,
|
|
ls_replica_loc))) {
|
|
LOG_WARN("get full ls replica location failed", K(ret), KPC(first_tablet_loc));
|
|
} else {
|
|
pc_ctx.sql_ctx_.get_reroute_info()->server_ = ls_replica_loc.get_server();
|
|
pc_ctx.sql_ctx_.get_reroute_info()->server_.set_port(static_cast<int32_t>(ls_replica_loc.get_sql_port()));
|
|
pc_ctx.sql_ctx_.get_reroute_info()->role_ = ls_replica_loc.get_role();
|
|
pc_ctx.sql_ctx_.get_reroute_info()->replica_type_ = ls_replica_loc.get_replica_type();
|
|
pc_ctx.sql_ctx_.get_reroute_info()->set_tbl_name(table_schema->get_table_name());
|
|
pc_ctx.sql_ctx_.get_reroute_info()->tbl_schema_version_ = table_schema->get_schema_version();
|
|
LOG_DEBUG("reroute sql", KPC(pc_ctx.sql_ctx_.get_reroute_info()));
|
|
need_reroute = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObSql::get_first_batched_multi_stmt(ObMultiStmtItem& multi_stmt_item, ObString& stmt_sql)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(multi_stmt_item.get_queries())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected null", K(ret), K(multi_stmt_item));
|
|
} else if (OB_UNLIKELY(multi_stmt_item.get_queries()->empty())) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get unexpected array count", K(ret));
|
|
} else {
|
|
stmt_sql = multi_stmt_item.get_queries()->at(0);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// OB_NOINLINE int ObSql::regenerate_physical_plan_with_baseline(const ObString& trimed_stmt,
|
|
// const ObPlanBaselineItem& baseline,
|
|
// ObSqlCtx& sql_ctx,
|
|
// ObResultSet& result,
|
|
// ObPlanCacheCtx& pc_ctx,
|
|
// const int get_plan_err,
|
|
// bool is_psmode)
|
|
// {
|
|
// int ret = OB_SUCCESS;
|
|
// ObString outlined_stmt = trimed_stmt;
|
|
// bool add_plan_to_pc = false;
|
|
// ObSQLSessionInfo &session = result.get_session();
|
|
// // record whether needs to do parameterization at this time,
|
|
// // if exact mode is on, not do parameterizaiton
|
|
// bool is_enable_transform_tree = !session.get_enable_exact_mode();
|
|
// //重新解析前将这两个标记reset掉,避免前面查plan cache的操作导致这两个参数在重新生成plan后会出现不幂等的问题
|
|
// pc_ctx.not_param_index_.reset();
|
|
// pc_ctx.neg_param_index_.reset();
|
|
// LOG_DEBUG("gen plan info", K(pc_ctx.bl_key_), K(get_plan_err));
|
|
|
|
// // note
|
|
// // sql_id 不需要重新生成了
|
|
|
|
|
|
// // for batched multi stmt, we only parse and optimize the first statement
|
|
// if (sql_ctx.multi_stmt_item_.is_batched_multi_stmt() &&
|
|
// OB_FAIL(get_first_batched_multi_stmt(sql_ctx.multi_stmt_item_, outlined_stmt))) {
|
|
// LOG_WARN("failed to get first batched stmt item", K(ret));
|
|
// } else if (OB_FAIL(ObSQLUtils::construct_outline_sql(pc_ctx.allocator_,
|
|
// session,
|
|
// baseline.outline_data_,
|
|
// outlined_stmt,
|
|
// true, //is_need_filter_hint
|
|
// outlined_stmt))) {
|
|
// LOG_WARN("fail to construct outline sql", K(ret), K(baseline.outline_data_), K(trimed_stmt));
|
|
// } else {
|
|
// pc_ctx.outlined_sql_len_ = outlined_stmt.length();
|
|
// LOG_DEBUG("contain baseline stmt", K(outlined_stmt));
|
|
// }
|
|
|
|
// if (OB_SUCC(ret)) {
|
|
// ParseResult parse_result;
|
|
// if (OB_FAIL(handle_parser(outlined_stmt,
|
|
// result.get_exec_context(),
|
|
// pc_ctx,
|
|
// parse_result,
|
|
// get_plan_err,
|
|
// add_plan_to_pc,
|
|
// is_enable_transform_tree))) {
|
|
// LOG_WARN("fail to parser and check", K(ret));
|
|
// } else if (OB_FAIL(generate_physical_plan(parse_result,
|
|
// &pc_ctx,
|
|
// sql_ctx,
|
|
// result,
|
|
// pc_ctx.is_begin_commit_stmt(),
|
|
// is_psmode))) {
|
|
// if (OB_ERR_PROXY_REROUTE == ret) {
|
|
// LOG_DEBUG("Failed to generate plan", K(ret));
|
|
// } else {
|
|
// LOG_WARN("Failed to generate plan", K(ret), K(result.get_exec_context().need_disconnect()));
|
|
// }
|
|
// } else if (!add_plan_to_pc) { // no need to check need_add_plan() again
|
|
// // 这个outline生成的计划不能加入到pc, 需要将状态设置成false
|
|
// }
|
|
// }
|
|
// return ret;
|
|
// }
|
|
|
|
}//end of namespace sql
|
|
}//end of namespace oceanbase
|