[FEAT MERGE] implement values statement
Co-authored-by: wangt1xiuyi <13547954130@163.com>
This commit is contained in:
@ -92,7 +92,7 @@ int ObPlanCacheObject::set_params_info(const ParamStore ¶ms)
|
||||
LOG_WARN("fail to get ext obj data type", K(ret));
|
||||
} else {
|
||||
param_info.ext_real_type_ = data_type.get_obj_type();
|
||||
param_info.scale_ = data_type.get_meta_type().get_scale();
|
||||
param_info.scale_ = data_type.get_scale();
|
||||
}
|
||||
LOG_DEBUG("ext params info", K(data_type), K(param_info), K(params.at(i)));
|
||||
} else {
|
||||
|
||||
@ -43,6 +43,7 @@
|
||||
#include "sql/spm/ob_spm_evolution_plan.h"
|
||||
#endif
|
||||
#include "pl/pl_cache/ob_pl_cache_mgr.h"
|
||||
#include "sql/plan_cache/ob_values_table_compression.h"
|
||||
|
||||
using namespace oceanbase::common;
|
||||
using namespace oceanbase::common::hash;
|
||||
@ -718,32 +719,35 @@ int ObPlanCache::construct_fast_parser_result(common::ObIAllocator &allocator,
|
||||
batch_count,
|
||||
first_truncated_sql))) {
|
||||
LOG_WARN("fail to do insert optimization", K(ret));
|
||||
} else if (!can_do_batch_insert) {
|
||||
// can't do batch insert
|
||||
} else if (OB_FAIL(rebuild_raw_params(allocator,
|
||||
pc_ctx,
|
||||
fp_result,
|
||||
batch_count))) {
|
||||
LOG_WARN("fail to rebuild raw_param", K(ret), K(batch_count));
|
||||
} else if (pc_ctx.insert_batch_opt_info_.multi_raw_params_.empty()) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected multi_raw_params, can't do batch insert opt, but not need to return error",
|
||||
K(batch_count), K(first_truncated_sql), K(pc_ctx.raw_sql_), K(fp_result));
|
||||
} else if (OB_ISNULL(pc_ctx.insert_batch_opt_info_.multi_raw_params_.at(0))) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected null ptr, can't do batch insert opt, but not need to return error",
|
||||
K(batch_count), K(first_truncated_sql), K(pc_ctx.raw_sql_), K(fp_result));
|
||||
} else {
|
||||
fp_result.raw_params_.reset();
|
||||
fp_result.raw_params_.set_allocator(&allocator);
|
||||
fp_result.raw_params_.set_capacity(pc_ctx.insert_batch_opt_info_.multi_raw_params_.at(0)->count());
|
||||
if (OB_FAIL(fp_result.raw_params_.assign(*pc_ctx.insert_batch_opt_info_.multi_raw_params_.at(0)))) {
|
||||
LOG_WARN("fail to assign raw_param", K(ret));
|
||||
} else if (can_do_batch_insert) {
|
||||
if (OB_FAIL(rebuild_raw_params(allocator,
|
||||
pc_ctx,
|
||||
fp_result,
|
||||
batch_count))) {
|
||||
LOG_WARN("fail to rebuild raw_param", K(ret), K(batch_count));
|
||||
} else if (pc_ctx.insert_batch_opt_info_.multi_raw_params_.empty()) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected multi_raw_params, can't do batch insert opt, but not need to return error",
|
||||
K(batch_count), K(first_truncated_sql), K(pc_ctx.raw_sql_), K(fp_result));
|
||||
} else if (OB_ISNULL(pc_ctx.insert_batch_opt_info_.multi_raw_params_.at(0))) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected null ptr, can't do batch insert opt, but not need to return error",
|
||||
K(batch_count), K(first_truncated_sql), K(pc_ctx.raw_sql_), K(fp_result));
|
||||
} else {
|
||||
pc_ctx.sql_ctx_.set_is_do_insert_batch_opt(batch_count);
|
||||
fp_result.pc_key_.name_.assign_ptr(first_truncated_sql.ptr(), first_truncated_sql.length());
|
||||
LOG_DEBUG("print new fp_result.pc_key_.name_", K(fp_result.pc_key_.name_));
|
||||
fp_result.raw_params_.reset();
|
||||
fp_result.raw_params_.set_allocator(&allocator);
|
||||
fp_result.raw_params_.set_capacity(pc_ctx.insert_batch_opt_info_.multi_raw_params_.at(0)->count());
|
||||
if (OB_FAIL(fp_result.raw_params_.assign(*pc_ctx.insert_batch_opt_info_.multi_raw_params_.at(0)))) {
|
||||
LOG_WARN("fail to assign raw_param", K(ret));
|
||||
} else {
|
||||
pc_ctx.sql_ctx_.set_is_do_insert_batch_opt(batch_count);
|
||||
fp_result.pc_key_.name_.assign_ptr(first_truncated_sql.ptr(), first_truncated_sql.length());
|
||||
LOG_DEBUG("print new fp_result.pc_key_.name_", K(fp_result.pc_key_.name_));
|
||||
}
|
||||
}
|
||||
} else if (OB_FAIL(ObValuesTableCompression::try_batch_exec_params(allocator, pc_ctx,
|
||||
*pc_ctx.sql_ctx_.session_info_, fp_result))) {
|
||||
LOG_WARN("failed to check fold params valid", K(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,6 +192,17 @@ struct PsNotParamInfo
|
||||
TO_STRING_KV(K_(idx), K_(ps_param));
|
||||
};
|
||||
|
||||
struct ObValuesTokenPos {
|
||||
ObValuesTokenPos() : no_param_sql_pos_(0), param_idx_(0) {}
|
||||
ObValuesTokenPos(const int64_t no_param_pos, const int64_t param_idx)
|
||||
: no_param_sql_pos_(no_param_pos), param_idx_(param_idx) {}
|
||||
int64_t no_param_sql_pos_;
|
||||
int64_t param_idx_;
|
||||
TO_STRING_KV(K(no_param_sql_pos_), K(param_idx_));
|
||||
};
|
||||
|
||||
typedef common::ObFixedArray<ObPCParam *, common::ObIAllocator> ObArrayPCParam;
|
||||
|
||||
struct ObFastParserResult
|
||||
{
|
||||
private:
|
||||
@ -203,7 +214,8 @@ public:
|
||||
raw_params_(&inner_alloc_),
|
||||
parameterized_params_(&inner_alloc_),
|
||||
cache_params_(NULL),
|
||||
values_token_pos_(0)
|
||||
values_token_pos_(0),
|
||||
values_tokens_(&inner_alloc_)
|
||||
{
|
||||
reset_question_mark_ctx();
|
||||
}
|
||||
@ -212,7 +224,9 @@ public:
|
||||
common::ObFixedArray<const common::ObObjParam *, common::ObIAllocator> parameterized_params_;
|
||||
ParamStore *cache_params_;
|
||||
ObQuestionMarkCtx question_mark_ctx_;
|
||||
int64_t values_token_pos_;
|
||||
int64_t values_token_pos_; // for insert values
|
||||
common::ObFixedArray<ObValuesTokenPos, common::ObIAllocator> values_tokens_; // for values table
|
||||
common::ObSEArray<ObArrayPCParam *, 4, common::ModulePageAllocator, true> array_params_;
|
||||
|
||||
void reset() {
|
||||
pc_key_.reset();
|
||||
@ -220,6 +234,8 @@ public:
|
||||
parameterized_params_.reuse();
|
||||
cache_params_ = NULL;
|
||||
values_token_pos_ = 0;
|
||||
values_tokens_.reuse();
|
||||
array_params_.reuse();
|
||||
}
|
||||
void reset_question_mark_ctx()
|
||||
{
|
||||
@ -230,7 +246,28 @@ public:
|
||||
question_mark_ctx_.by_name_ = false;
|
||||
question_mark_ctx_.by_defined_name_ = false;
|
||||
}
|
||||
TO_STRING_KV(K(pc_key_), K(raw_params_), K(parameterized_params_), K(cache_params_), K(values_token_pos_));
|
||||
int assign(const ObFastParserResult &other)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
pc_key_ = other.pc_key_;
|
||||
raw_params_.set_allocator(&inner_alloc_);
|
||||
parameterized_params_.set_allocator(&inner_alloc_);
|
||||
cache_params_ = other.cache_params_;
|
||||
question_mark_ctx_ = other.question_mark_ctx_;
|
||||
values_tokens_.set_allocator(&inner_alloc_);
|
||||
if (OB_FAIL(raw_params_.assign(other.raw_params_))) {
|
||||
SQL_PC_LOG(WARN, "failed to assign fix array", K(ret));
|
||||
} else if (OB_FAIL(parameterized_params_.assign(other.parameterized_params_))) {
|
||||
SQL_PC_LOG(WARN, "failed to assign fix array", K(ret));
|
||||
} else if (OB_FAIL(values_tokens_.assign(other.values_tokens_))) {
|
||||
SQL_PC_LOG(WARN, "failed to assign fix array", K(ret));
|
||||
} else if (OB_FAIL(array_params_.assign(other.array_params_))) {
|
||||
SQL_PC_LOG(WARN, "failed to assign array", K(ret));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
TO_STRING_KV(K(pc_key_), K(raw_params_), K(parameterized_params_), K(cache_params_), K(values_token_pos_),
|
||||
K(values_tokens_), K(array_params_));
|
||||
};
|
||||
|
||||
enum WayToGenPlan {
|
||||
@ -341,6 +378,7 @@ struct ObPlanCacheCtx : public ObILibCacheCtx
|
||||
is_inner_sql_(false),
|
||||
is_original_ps_mode_(false),
|
||||
ab_params_(NULL),
|
||||
new_raw_sql_(),
|
||||
is_rewrite_sql_(false),
|
||||
rule_name_(),
|
||||
def_name_ctx_(NULL),
|
||||
@ -419,6 +457,7 @@ struct ObPlanCacheCtx : public ObILibCacheCtx
|
||||
K(dynamic_param_info_list_),
|
||||
K(tpl_sql_const_cons_),
|
||||
K(is_original_ps_mode_),
|
||||
K(new_raw_sql_),
|
||||
K(need_retry_add_plan_),
|
||||
K(insert_batch_opt_info_)
|
||||
);
|
||||
@ -469,6 +508,7 @@ struct ObPlanCacheCtx : public ObILibCacheCtx
|
||||
bool is_inner_sql_;
|
||||
bool is_original_ps_mode_;
|
||||
ParamStore *ab_params_; // arraybinding batch parameters,
|
||||
ObString new_raw_sql_; // values clause rebuild raw sql
|
||||
|
||||
// ********** for rewrite rule **********
|
||||
bool is_rewrite_sql_;
|
||||
|
||||
@ -29,6 +29,8 @@
|
||||
#include "share/ob_duplicate_scope_define.h"
|
||||
#include "pl/ob_pl_stmt.h"
|
||||
#include "share/resource_manager/ob_resource_manager.h"
|
||||
#include "sql/plan_cache/ob_values_table_compression.h"
|
||||
|
||||
using namespace oceanbase::share::schema;
|
||||
using namespace oceanbase::common;
|
||||
using namespace oceanbase::pl;
|
||||
@ -175,6 +177,7 @@ ObPlanCacheValue::ObPlanCacheValue()
|
||||
need_param_(true),
|
||||
is_nested_sql_(false),
|
||||
is_batch_execute_(false),
|
||||
has_dynamic_values_table_(false),
|
||||
stored_schema_objs_(pc_alloc_),
|
||||
stmt_type_(stmt::T_MAX)
|
||||
{
|
||||
@ -266,6 +269,7 @@ int ObPlanCacheValue::init(ObPCVSet *pcv_set, const ObILibCacheObject *cache_obj
|
||||
need_param_ = plan->need_param();
|
||||
is_nested_sql_ = ObSQLUtils::is_nested_sql(&pc_ctx.exec_ctx_);
|
||||
is_batch_execute_ = pc_ctx.sql_ctx_.is_batch_params_execute();
|
||||
has_dynamic_values_table_ = pc_ctx.exec_ctx_.has_dynamic_values_table();
|
||||
MEMCPY(sql_id_, pc_ctx.sql_ctx_.sql_id_, sizeof(pc_ctx.sql_ctx_.sql_id_));
|
||||
if (OB_FAIL(not_param_index_.add_members2(pc_ctx.not_param_index_))) {
|
||||
LOG_WARN("fail to add not param index members", K(ret));
|
||||
@ -520,6 +524,12 @@ int ObPlanCacheValue::choose_plan(ObPlanCacheCtx &pc_ctx,
|
||||
LOG_WARN("failed to resolver row params", K(ret));
|
||||
}
|
||||
}
|
||||
} else if (OB_UNLIKELY(pc_ctx.exec_ctx_.has_dynamic_values_table())) {
|
||||
if (OB_FAIL(ObValuesTableCompression::resolve_params_for_values_clause(pc_ctx, stmt_type_,
|
||||
not_param_info_, param_charset_type_, neg_param_index_, not_param_index_,
|
||||
must_be_positive_idx_, params))) {
|
||||
LOG_WARN("failed to resolve_params_for_values_clause ", K(ret));
|
||||
}
|
||||
} else if (OB_FAIL(resolver_params(pc_ctx,
|
||||
stmt_type_,
|
||||
param_charset_type_,
|
||||
@ -669,124 +679,39 @@ int ObPlanCacheValue::resolver_params(ObPlanCacheCtx &pc_ctx,
|
||||
const stmt::StmtType stmt_type,
|
||||
const ObIArray<ObCharsetType> ¶m_charset_type,
|
||||
const ObBitSet<> &neg_param_index,
|
||||
const ObBitSet<> ¬_param_index_,
|
||||
const ObBitSet<> ¬_param_index,
|
||||
const ObBitSet<> &must_be_positive_idx,
|
||||
ObIArray<ObPCParam *> &raw_params,
|
||||
ParamStore *obj_params)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
ObSQLSessionInfo *session = pc_ctx.exec_ctx_.get_my_session();
|
||||
ParseNode *raw_param = NULL;
|
||||
ObPhysicalPlanCtx *phy_ctx = pc_ctx.exec_ctx_.get_physical_plan_ctx();
|
||||
const int64_t raw_param_cnt = raw_params.count();
|
||||
ObObjParam value;
|
||||
if (OB_ISNULL(session)) {
|
||||
if (OB_ISNULL(session) || OB_ISNULL(phy_ctx)) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
SQL_PC_LOG(WARN, "invalid argument", K(ret), KP(session));
|
||||
} else if (obj_params != NULL && PC_PS_MODE != pc_ctx.mode_ && PC_PL_MODE != pc_ctx.mode_) {
|
||||
ObCollationType collation_connection = static_cast<ObCollationType>(
|
||||
session->get_local_collation_connection());
|
||||
int64_t N = raw_params.count();
|
||||
(void)obj_params->reserve(N);
|
||||
if (N != param_charset_type.count()) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("raw_params and param_charset_type count is different",
|
||||
K(N), K(param_charset_type.count()),
|
||||
K(pc_ctx.raw_sql_), K(ret));
|
||||
SQL_PC_LOG(WARN, "invalid argument", K(ret), KP(session), KP(phy_ctx));
|
||||
} else if (obj_params == NULL || PC_PS_MODE == pc_ctx.mode_ || PC_PL_MODE == pc_ctx.mode_) {
|
||||
/* do nothing */
|
||||
} else if (OB_UNLIKELY(raw_param_cnt != param_charset_type.count())) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
SQL_PC_LOG(WARN, "raw_params and param_charset_type count is different", K(ret),
|
||||
K(raw_param_cnt), K(param_charset_type.count()), K(pc_ctx.raw_sql_));
|
||||
} else {
|
||||
CHECK_COMPATIBILITY_MODE(session);
|
||||
ObCollationType collation_connection = static_cast<ObCollationType>(session->get_local_collation_connection());
|
||||
(void)obj_params->reserve(raw_param_cnt);
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < raw_param_cnt; i++) {
|
||||
bool is_param = false;
|
||||
if (OB_FAIL(ObResolverUtils::resolver_param(pc_ctx, *session, phy_ctx->get_param_store_for_update(), stmt_type,
|
||||
param_charset_type.at(i), neg_param_index, not_param_index, must_be_positive_idx,
|
||||
raw_params.at(i), i, value, is_param))) {
|
||||
SQL_PC_LOG(WARN, "failed to resolver param", K(ret), K(i));
|
||||
} else if (is_param && OB_FAIL(obj_params->push_back(value))) {
|
||||
SQL_PC_LOG(WARN, "fail to push item to array", K(ret));
|
||||
} else {/* do nothing */}
|
||||
}
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < N; i++) {
|
||||
value.reset();
|
||||
if (OB_ISNULL(raw_params.at(i))) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("invalid argument", K(ret), K(raw_params.at(i)));
|
||||
} else if (NULL == (raw_param = raw_params.at(i)->node_)) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("invalid argument", K(ret), K(raw_param));
|
||||
} else if (!not_param_index_.has_member(i)) { //not param
|
||||
if (neg_param_index.has_member(i)) {
|
||||
// select - 1.2 from dual
|
||||
// "- 1.2" will be treated as a const node with neg sign
|
||||
// however, ObNumber::from("- 1.2") will throw a error, for there are spaces between neg sign and num
|
||||
// so remove spaces before resolve_const is called
|
||||
if (OB_FAIL(rm_space_for_neg_num(raw_param, pc_ctx.allocator_))) {
|
||||
SQL_PC_LOG(WARN, "fail to remove spaces for neg node", K(ret));
|
||||
}
|
||||
}
|
||||
if (OB_FAIL(ret)) {
|
||||
} else if (OB_FAIL(handle_varchar_charset(param_charset_type.at(i),
|
||||
pc_ctx.allocator_,
|
||||
raw_param))) {
|
||||
SQL_PC_LOG(WARN, "fail to handle varchar charset");
|
||||
}
|
||||
ObString literal_prefix;
|
||||
const bool is_paramlize = false;
|
||||
CHECK_COMPATIBILITY_MODE(session);
|
||||
int64_t server_collation = CS_TYPE_INVALID;
|
||||
if (OB_SUCC(ret) && T_QUESTIONMARK == raw_param->type_) {
|
||||
ObPhysicalPlanCtx *phy_ctx = pc_ctx.exec_ctx_.get_physical_plan_ctx();
|
||||
int64_t idx = raw_param->value_;
|
||||
CK (nullptr != phy_ctx);
|
||||
CK (idx >= 0 && idx < phy_ctx->get_param_store_for_update().count());
|
||||
OX (value.set_is_boolean(phy_ctx->get_param_store_for_update().at(idx).is_boolean()));
|
||||
}
|
||||
if (OB_FAIL(ret)) {
|
||||
} 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));
|
||||
} else if (OB_FAIL(ObResolverUtils::resolve_const(raw_param,
|
||||
stmt_type,
|
||||
pc_ctx.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 (FALSE_IT(value.set_raw_text_info(
|
||||
static_cast<int32_t>(raw_param->raw_sql_offset_),
|
||||
static_cast<int32_t>(raw_param->text_len_)))) {
|
||||
// nothing.
|
||||
} else if (OB_FAIL(obj_params->push_back(value))) {
|
||||
SQL_PC_LOG(WARN, "fail to push item to array", K(ret));
|
||||
} else if (ob_is_numeric_type(value.get_type())) {
|
||||
if (must_be_positive_idx.has_member(i)) {
|
||||
if (value.is_boolean()) {
|
||||
// boolean will skip this check
|
||||
} else if (lib::is_oracle_mode()
|
||||
&& (value.is_negative_number()
|
||||
|| (value.is_zero_number() && '-' == raw_param->str_value_[0]))) { // -0 is also counted as negative
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_TRACE("param must be positive", K(ret), K(i), K(value));
|
||||
pc_ctx.should_add_plan_ = false; // 内部主动抛出not supported时候需要设置这个标志,以免新计划add plan导致锁冲突
|
||||
} else if (lib::is_mysql_mode()
|
||||
&& value.is_integer_type()
|
||||
&& (value.get_int() < 0
|
||||
|| (0 == value.get_int() && '-' == raw_param->str_value_[0]))) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_TRACE("param must be positive", K(ret), K(i), K(value));
|
||||
pc_ctx.should_add_plan_ = false; // 内部主动抛出not supported时候需要设置这个标志,以免新计划add plan导致锁冲突
|
||||
} else {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
SQL_PC_LOG(TRACE, "is_param",
|
||||
K(i),
|
||||
K(value),
|
||||
K(raw_param->type_),
|
||||
K(raw_param->value_),
|
||||
"str_value", ObString(raw_param->str_len_, raw_param->str_value_));
|
||||
} else {
|
||||
SQL_PC_LOG(TRACE, "not_param",
|
||||
K(i),
|
||||
K(value),
|
||||
K(raw_param->type_),
|
||||
K(raw_param->value_),
|
||||
"str_value", ObString(raw_param->str_len_, raw_param->str_value_));
|
||||
}
|
||||
} // for end
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -1493,6 +1418,7 @@ void ObPlanCacheValue::reset()
|
||||
contain_sys_name_table_ = false;
|
||||
is_nested_sql_ = false;
|
||||
is_batch_execute_ = false;
|
||||
has_dynamic_values_table_ = false;
|
||||
for (int64_t i = 0; i < stored_schema_objs_.count(); i++) {
|
||||
if (OB_ISNULL(stored_schema_objs_.at(i)) || OB_ISNULL(pc_alloc_)) {
|
||||
// do nothing
|
||||
@ -1697,7 +1623,8 @@ int ObPlanCacheValue::match(ObPlanCacheCtx &pc_ctx,
|
||||
//because nested sql's plan be forced to use DAS plan
|
||||
//but the general sql's plan has no this constraint
|
||||
is_same = false;
|
||||
} else if (is_batch_execute_ != pc_ctx.sql_ctx_.is_batch_params_execute()) {
|
||||
} else if (is_batch_execute_ != pc_ctx.sql_ctx_.is_batch_params_execute()||
|
||||
has_dynamic_values_table_ != pc_ctx.exec_ctx_.has_dynamic_values_table()) {
|
||||
// the plan of batch execute sql can't match with the plan of general sql
|
||||
is_same = false;
|
||||
} else if (!need_param_) {
|
||||
@ -1742,43 +1669,6 @@ int ObPlanCacheValue::match(ObPlanCacheCtx &pc_ctx,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObPlanCacheValue::handle_varchar_charset(ObCharsetType charset_type,
|
||||
ObIAllocator &allocator,
|
||||
ParseNode *&node)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
if ((T_HEX_STRING == node->type_ || T_VARCHAR == node->type_)
|
||||
&& CHARSET_INVALID != charset_type) {
|
||||
ParseNode *charset_node = new_node(&allocator, T_CHARSET, 0);
|
||||
ParseNode *varchar_node = NULL;
|
||||
if (T_HEX_STRING == node->type_) {
|
||||
varchar_node = new_non_terminal_node(&allocator, T_VARCHAR, 1, charset_node);
|
||||
} else if (T_VARCHAR == node->type_) {
|
||||
varchar_node = new_non_terminal_node(&allocator, T_VARCHAR, 2, charset_node, node);
|
||||
}
|
||||
|
||||
if (OB_ISNULL(charset_node) || OB_ISNULL(varchar_node)) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
} else {
|
||||
const char *name = ObCharset::charset_name(charset_type);
|
||||
charset_node->str_value_ = parse_strdup(name, &allocator, &(charset_node->str_len_));
|
||||
if (NULL == charset_node->str_value_) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
} else {
|
||||
varchar_node->str_value_ = node->str_value_;
|
||||
varchar_node->str_len_ = node->str_len_;
|
||||
varchar_node->raw_text_ = node->raw_text_;
|
||||
varchar_node->text_len_ = node->text_len_;
|
||||
varchar_node->type_ = T_VARCHAR;
|
||||
|
||||
node = varchar_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ObPlanCacheValue::is_contain_tmp_tbl() const
|
||||
{
|
||||
bool is_contain = false;
|
||||
@ -2305,39 +2195,6 @@ int ObPlanCacheValue::lift_tenant_schema_version(int64_t new_schema_version)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObPlanCacheValue::rm_space_for_neg_num(ParseNode *param_node, ObIAllocator &allocator)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
char *buf = NULL;
|
||||
int64_t pos = 0;
|
||||
int64_t idx = 0;
|
||||
if (param_node->str_len_ <= 0) {
|
||||
// do nothing
|
||||
} else if ('-' != param_node->str_value_[idx]) {
|
||||
// 'select - 1.2 from dual' and 'select 1.2 from dual' will hit the same plan, the key is
|
||||
// select ? from dual, so '- 1.2' and '1.2' will all go here, if '-' is not presented,
|
||||
// do nothing
|
||||
LOG_TRACE("rm space for neg num", K(idx), K(ObString(param_node->str_len_, param_node->str_value_)));
|
||||
} else if (OB_ISNULL(buf = (char *)allocator.alloc(param_node->str_len_))) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
LOG_WARN("failed to allocator memory", K(ret), K(param_node->str_len_));
|
||||
} else {
|
||||
buf[pos++] = '-';
|
||||
idx += 1;
|
||||
for (; idx < param_node->str_len_ && isspace(param_node->str_value_[idx]); idx++);
|
||||
int32_t len = (int32_t)(param_node->str_len_ - idx);
|
||||
if (len > 0) {
|
||||
MEMCPY(buf + pos, param_node->str_value_ + idx, len);
|
||||
}
|
||||
pos += len;
|
||||
param_node->str_value_ = buf;
|
||||
param_node->str_len_ = pos;
|
||||
|
||||
LOG_DEBUG("rm space for neg num", K(idx), K(ObString(param_node->str_len_, param_node->str_value_)));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObPlanCacheValue::check_contains_table(uint64_t db_id, common::ObString tab_name, bool &contains)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
|
||||
@ -300,11 +300,6 @@ private:
|
||||
share::schema::ObSchemaObjVersion &local_outline_version);
|
||||
|
||||
int get_outline_param_index(ObExecContext &exec_ctx, int64_t ¶m_idx) const;
|
||||
|
||||
static int handle_varchar_charset(ObCharsetType charset_type,
|
||||
ObIAllocator &allocator,
|
||||
ParseNode *&node);
|
||||
|
||||
/**
|
||||
* @brief if there is a temporary table in dependency tables
|
||||
* @retval is_contain: true for containing temporary table
|
||||
@ -355,9 +350,6 @@ private:
|
||||
int need_check_schema_version(ObPlanCacheCtx &pc_ctx,
|
||||
int64_t &new_schema_version,
|
||||
bool &need_check);
|
||||
|
||||
static int rm_space_for_neg_num(ParseNode *param_node, ObIAllocator &allocator);
|
||||
|
||||
int assign_udr_infos(ObPlanCacheCtx &pc_ctx);
|
||||
void reset_tpl_sql_const_cons();
|
||||
int check_tpl_sql_const_cons(const ObFastParserResult &fp_result,
|
||||
@ -420,6 +412,7 @@ private:
|
||||
//Therefore, it is necessary to distinguish whether it is nested SQL or not.
|
||||
bool is_nested_sql_;
|
||||
bool is_batch_execute_;
|
||||
bool has_dynamic_values_table_;
|
||||
// only when not need to param, this feild will be used.
|
||||
common::ObString raw_sql_;
|
||||
common::ObFixedArray<PCVSchemaObj *, common::ObIAllocator> stored_schema_objs_;
|
||||
|
||||
@ -1034,10 +1034,15 @@ int ObSqlParameterization::parameterize_syntax_tree(common::ObIAllocator &alloca
|
||||
fp_ctx.sql_mode_ = session->get_sql_mode();
|
||||
fp_ctx.is_udr_mode_ = pc_ctx.is_rewrite_sql_;
|
||||
fp_ctx.def_name_ctx_ = pc_ctx.def_name_ctx_;
|
||||
ObString raw_sql = pc_ctx.raw_sql_;
|
||||
if (pc_ctx.sql_ctx_.is_do_insert_batch_opt()) {
|
||||
raw_sql = pc_ctx.insert_batch_opt_info_.new_reconstruct_sql_;
|
||||
} else if (pc_ctx.exec_ctx_.has_dynamic_values_table()) {
|
||||
raw_sql = pc_ctx.new_raw_sql_;
|
||||
}
|
||||
if (OB_FAIL(fast_parser(allocator,
|
||||
fp_ctx,
|
||||
pc_ctx.sql_ctx_.is_do_insert_batch_opt() ?
|
||||
pc_ctx.insert_batch_opt_info_.new_reconstruct_sql_ : pc_ctx.raw_sql_,
|
||||
raw_sql,
|
||||
pc_ctx.fp_result_))) {
|
||||
SQL_PC_LOG(WARN, "fail to fast parser", K(ret));
|
||||
}
|
||||
@ -1474,8 +1479,8 @@ int ObSqlParameterization::fast_parser(ObIAllocator &allocator,
|
||||
|| (ObParser::is_pl_stmt(sql, nullptr, &is_call_procedure) && !is_call_procedure))) {
|
||||
(void)fp_result.pc_key_.name_.assign_ptr(sql.ptr(), sql.length());
|
||||
} else if (GCONF._ob_enable_fast_parser) {
|
||||
if (OB_FAIL(ObFastParser::parse(sql, fp_ctx, allocator, no_param_sql_ptr,
|
||||
no_param_sql_len, p_list, param_num, fp_result.question_mark_ctx_, fp_result.values_token_pos_))) {
|
||||
if (OB_FAIL(ObFastParser::parse(sql, fp_ctx, allocator, no_param_sql_ptr, no_param_sql_len,
|
||||
p_list, param_num, fp_result, fp_result.values_token_pos_))) {
|
||||
LOG_WARN("fast parse error", K(param_num),
|
||||
K(ObString(no_param_sql_len, no_param_sql_ptr)), K(sql));
|
||||
}
|
||||
|
||||
824
src/sql/plan_cache/ob_values_table_compression.cpp
Normal file
824
src/sql/plan_cache/ob_values_table_compression.cpp
Normal file
@ -0,0 +1,824 @@
|
||||
#define USING_LOG_PREFIX SQL_PC
|
||||
#include "sql/plan_cache/ob_values_table_compression.h"
|
||||
#include "sql/plan_cache/ob_plan_cache_struct.h"
|
||||
#include "sql/parser/ob_fast_parser.h"
|
||||
#include "sql/engine/ob_exec_context.h"
|
||||
#include "sql/resolver/ob_resolver_utils.h"
|
||||
#include "sql/engine/expr/ob_expr_version.h"
|
||||
|
||||
using namespace oceanbase::common;
|
||||
|
||||
namespace oceanbase
|
||||
{
|
||||
|
||||
namespace sql
|
||||
{
|
||||
// based in ob_parser.h
|
||||
const char *ObValuesTableCompression::lower_[ObParser::S_MAX] = {
|
||||
"", "", "", "", "", "", "", "", "", "", /* 0 ~9 */
|
||||
"", "", "", "update", "", "", "", "", "", "", /* 10 ~19 */
|
||||
"", "", "", "", "", "", "", "", "", "", /* 20 ~29 */
|
||||
"", "", "", "select", "insert", "delete", "values", "table", "into" /* 30 ~38 */
|
||||
};
|
||||
|
||||
const char *ObValuesTableCompression::upper_[ObParser::S_MAX] = {
|
||||
"", "", "", "", "", "", "", "", "", "", /* 0 ~9 */
|
||||
"", "", "", "UPDATE", "", "", "", "", "", "", /* 10 ~19 */
|
||||
"", "", "", "", "", "", "", "", "", "", /* 20 ~29 */
|
||||
"", "", "", "SELECT", "INSERT", "DELETE", "VALUES", "TABLE", "INTO" /* 30 ~38 */
|
||||
};
|
||||
|
||||
#define ISSPACE(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || (c) == '\t' || (c) == '\f' || (c) == '\v')
|
||||
|
||||
void ObValuesTableCompression::match_one_state(const char *&p,
|
||||
const char *p_end,
|
||||
const ObParser::State next_state,
|
||||
ObParser::State &state)
|
||||
{
|
||||
int compare_len = strlen(lower_[state]);
|
||||
if (p_end - p < compare_len) {
|
||||
state = ObParser::S_INVALID;
|
||||
} else if (0 == strncasecmp(p, lower_[state], compare_len)) {
|
||||
p += compare_len;
|
||||
state = next_state;
|
||||
} else {
|
||||
state = ObParser::S_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
bool ObValuesTableCompression::is_support_compress_values_table(const ObString &stmt)
|
||||
{
|
||||
ObParser::State state = ObParser::S_START;
|
||||
ObParser::State save_state = state;
|
||||
const char *p = stmt.ptr();
|
||||
const char *p_start = p;
|
||||
const char *p_end = p + stmt.length();
|
||||
bool is_dml_stmt = false;
|
||||
bool has_error = false;
|
||||
while (p < p_end && !has_error && !is_dml_stmt) {
|
||||
switch (state) {
|
||||
case ObParser::S_START: {
|
||||
if (ISSPACE(*p)) {
|
||||
p++;
|
||||
} else {
|
||||
if (!ObParser::is_comment(p, p_end, save_state, state, ObParser::S_INVALID) &&
|
||||
state != ObParser::S_INVALID) {
|
||||
if (ObParser::S_START == state) {
|
||||
save_state = state;
|
||||
if (*p == lower_[ObParser::S_SELECT][0] || *p == upper_[ObParser::S_SELECT][0]) {
|
||||
state = ObParser::S_SELECT;
|
||||
} else if (*p == lower_[ObParser::S_INSERT][0] || *p == upper_[ObParser::S_INSERT][0]) {
|
||||
state = ObParser::S_INSERT;
|
||||
} else if (*p == lower_[ObParser::S_UPDATE][0] || *p == upper_[ObParser::S_UPDATE][0]) {
|
||||
state = ObParser::S_UPDATE;
|
||||
} else if (*p == lower_[ObParser::S_DELETE][0] || *p == upper_[ObParser::S_DELETE][0]) {
|
||||
state = ObParser::S_DELETE;
|
||||
} else if (*p == lower_[ObParser::S_VALUES][0] || *p == upper_[ObParser::S_VALUES][0]) {
|
||||
state = ObParser::S_VALUES;
|
||||
} else {
|
||||
state = ObParser::S_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case ObParser::S_SELECT:
|
||||
case ObParser::S_DELETE:
|
||||
case ObParser::S_UPDATE:
|
||||
case ObParser::S_VALUES: {
|
||||
match_one_state(p, p_end, ObParser::S_NORMAL, state);
|
||||
} break;
|
||||
case ObParser::S_INSERT: {
|
||||
match_one_state(p, p_end, ObParser::S_INTO, state);
|
||||
} break;
|
||||
case ObParser::S_INTO: {
|
||||
if (ISSPACE(*p)) {
|
||||
p++;
|
||||
} else {
|
||||
if (!ObParser::is_comment(p, p_end, save_state, state, ObParser::S_INVALID) &&
|
||||
state != ObParser::S_INVALID) {
|
||||
match_one_state(p, p_end, ObParser::S_NORMAL, state);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case ObParser::S_NORMAL: {
|
||||
is_dml_stmt = true;
|
||||
has_error = false;
|
||||
} break;
|
||||
case ObParser::S_COMMENT: {
|
||||
if (*p == '\n') {
|
||||
// end of '--' comments
|
||||
state = save_state;
|
||||
}
|
||||
p++;
|
||||
} break;
|
||||
case ObParser::S_C_COMMENT: {
|
||||
if (*p == '*') {
|
||||
if ((p + 1 < p_end) && '/' == *(p + 1)) {
|
||||
// end of '/**/' comments
|
||||
state = save_state;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
} break;
|
||||
case ObParser::S_INVALID:
|
||||
default: {
|
||||
is_dml_stmt = false;
|
||||
has_error = true;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
return is_dml_stmt && !has_error;
|
||||
}
|
||||
|
||||
int ObValuesTableCompression::add_raw_array_params(ObIAllocator &allocator,
|
||||
ObPlanCacheCtx &pc_ctx,
|
||||
const ObFastParserResult &fp_result,
|
||||
const int64_t begin_param,
|
||||
const int64_t row_count,
|
||||
const int64_t param_count)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
if (begin_param + row_count * param_count > fp_result.raw_params_.count() ||
|
||||
row_count <= 0) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected raw_params", K(ret), K(begin_param), K(row_count), K(param_count),
|
||||
K(fp_result.raw_params_.count()));
|
||||
} else {
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < param_count; ++i) {
|
||||
void *buf = nullptr;
|
||||
ObArrayPCParam *params_array = nullptr;
|
||||
if (OB_ISNULL(buf = allocator.alloc(sizeof(ObArrayPCParam)))) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
LOG_WARN("fail to alloc memory", K(ret), K(sizeof(ObArrayPCParam)));
|
||||
} else {
|
||||
params_array = new(buf) ObArrayPCParam(allocator);
|
||||
params_array->set_capacity(row_count);
|
||||
}
|
||||
for (int64_t j = 0; OB_SUCC(ret) && j < row_count; ++j) {
|
||||
int64_t param_idx = begin_param + j * param_count + i;
|
||||
if (OB_FAIL(params_array->push_back(fp_result.raw_params_.at(param_idx)))) {
|
||||
LOG_WARN("fail to push back", K(ret), K(i), K(j));
|
||||
}
|
||||
}
|
||||
if (OB_FAIL(ret)) {
|
||||
} else if (OB_FAIL(pc_ctx.fp_result_.array_params_.push_back(params_array))) {
|
||||
LOG_WARN("fail to push params array", K(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObValuesTableCompression::rebuild_new_raw_sql(ObPlanCacheCtx &pc_ctx,
|
||||
const ObIArray<ObPCParam*> &raw_params,
|
||||
const int64_t begin_idx,
|
||||
const int64_t param_cnt,
|
||||
const int64_t delta_length,
|
||||
const ObString &no_param_sql,
|
||||
ObString &new_raw_sql,
|
||||
int64_t &no_param_sql_pos,
|
||||
int64_t &new_raw_pos)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
char *buff = new_raw_sql.ptr();
|
||||
int64_t buff_len = pc_ctx.raw_sql_.length();
|
||||
int64_t len = 0;
|
||||
if (OB_ISNULL(buff)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("buff is null", K(ret), KP(buff));
|
||||
} else if (begin_idx < 0 || raw_params.count() < begin_idx + param_cnt) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("param is wrong", K(ret), K(begin_idx), K(param_cnt));
|
||||
} else {
|
||||
for (int64_t i = begin_idx; OB_SUCC(ret) && i < begin_idx + param_cnt; i++) {
|
||||
const ObPCParam *pc_param = raw_params.at(i);
|
||||
if (OB_ISNULL(pc_param) || OB_ISNULL(pc_param->node_)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected NULL ptr", K(ret), KP(pc_param));
|
||||
} else {
|
||||
int64_t param_pos = pc_param->node_->pos_ - delta_length; // get pos is in new no param sql
|
||||
int64_t param_len = pc_param->node_->text_len_;
|
||||
len = param_pos - no_param_sql_pos;
|
||||
if (OB_UNLIKELY(len < 0) || OB_UNLIKELY(new_raw_pos + len + param_len > buff_len)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected params", K(ret), K(len), K(param_len), K(new_raw_pos));
|
||||
} else {
|
||||
if (len > 0) {
|
||||
//copy text
|
||||
MEMCPY(buff + new_raw_pos, no_param_sql.ptr() + no_param_sql_pos, len);
|
||||
new_raw_pos += len;
|
||||
no_param_sql_pos += len;
|
||||
}
|
||||
if (param_pos == no_param_sql_pos) {
|
||||
//copy raw param
|
||||
MEMCPY(buff + new_raw_pos, pc_param->node_->raw_text_, param_len);
|
||||
new_raw_pos += param_len;
|
||||
no_param_sql_pos += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (OB_SUCC(ret)) {
|
||||
new_raw_sql.assign_ptr(buff, new_raw_pos);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObValuesTableCompression::try_batch_exec_params(ObIAllocator &allocator,
|
||||
ObPlanCacheCtx &pc_ctx,
|
||||
ObSQLSessionInfo &session_info,
|
||||
ObFastParserResult &fp_result)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
bool can_fold_params = false;
|
||||
// used for no_param_sql --> new_no_param_sql
|
||||
int64_t old_sql_pos = 0;
|
||||
int64_t new_sql_pos = 0;
|
||||
int64_t array_param_idx = 0;
|
||||
int64_t last_raw_param_idx = 0;
|
||||
int64_t new_raw_idx = 0;
|
||||
int64_t total_delta_len = 0;
|
||||
ObString new_no_param_sql;
|
||||
ObSEArray<ObPCParam*, 4> temp_store;
|
||||
char *buff = NULL;
|
||||
int64_t buff_len = pc_ctx.raw_sql_.length();
|
||||
int64_t no_param_sql_pos = 0;
|
||||
int64_t new_raw_sql_pos = 0;
|
||||
ObString &new_raw_sql = pc_ctx.new_raw_sql_;
|
||||
ObSEArray<int64_t, 16> raw_pos;
|
||||
ObPhysicalPlanCtx *phy_ctx = NULL;
|
||||
uint64_t data_version = 0;
|
||||
if (OB_FAIL(GET_MIN_DATA_VERSION(session_info.get_effective_tenant_id(), data_version))) {
|
||||
LOG_WARN("get tenant data version failed", K(ret), K(session_info.get_effective_tenant_id()));
|
||||
} else if (pc_ctx.sql_ctx_.handle_batched_multi_stmt() ||
|
||||
lib::is_oracle_mode() ||
|
||||
session_info.is_inner() ||
|
||||
session_info.get_is_in_retry() ||
|
||||
fp_result.values_tokens_.empty() ||
|
||||
data_version < DATA_VERSION_4_2_1_0 ||
|
||||
!is_support_compress_values_table(pc_ctx.raw_sql_)) {
|
||||
/* do nothing */
|
||||
} else if (OB_ISNULL(phy_ctx = pc_ctx.exec_ctx_.get_physical_plan_ctx())) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected NULL ptr", K(ret));
|
||||
} else {
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < fp_result.values_tokens_.count(); ++i) {
|
||||
bool is_valid = false;
|
||||
int64_t values_token_pos = fp_result.values_tokens_.at(i).no_param_sql_pos_;
|
||||
int64_t param_idx = fp_result.values_tokens_.at(i).param_idx_; // idx in fp_result.raw_params_
|
||||
int64_t batch_count = 0;
|
||||
int64_t param_count = 0;
|
||||
int64_t delta_len = 0;
|
||||
if (OB_FAIL(ObValuesTableCompression::parser_values_row_str(allocator, fp_result.pc_key_.name_,
|
||||
values_token_pos, new_no_param_sql, old_sql_pos,
|
||||
new_sql_pos, batch_count, param_count, delta_len,
|
||||
is_valid))) {
|
||||
LOG_WARN("fail to parser insert string", K(ret), K(fp_result.pc_key_.name_));
|
||||
} else if (!is_valid || param_count <= 0 || batch_count <= 1 || delta_len <= 0) {
|
||||
LOG_TRACE("can not do batch opt", K(ret), K(is_valid), K(param_count), K(batch_count), K(delta_len));
|
||||
} else if (OB_FAIL(add_raw_array_params(allocator, pc_ctx, fp_result, param_idx, batch_count,
|
||||
param_count))) {
|
||||
LOG_WARN("fail to rebuild raw_param", K(ret));
|
||||
} else {
|
||||
if (!can_fold_params) {
|
||||
if (OB_ISNULL(buff = (char *)allocator.alloc(buff_len))) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("buff is null", K(ret), KP(buff));
|
||||
} else {
|
||||
new_raw_sql.assign_ptr(buff, buff_len);
|
||||
}
|
||||
}
|
||||
for (int64_t j = last_raw_param_idx; OB_SUCC(ret) && j < param_idx + param_count; j++) {
|
||||
ObPCParam *pc_param = pc_ctx.fp_result_.raw_params_.at(j);
|
||||
if (OB_ISNULL(pc_param) || OB_ISNULL(pc_param->node_)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("pc_param is null", K(ret), KP(pc_param));
|
||||
} else if (OB_FAIL(temp_store.push_back(pc_param))) {
|
||||
LOG_WARN("failed to push back", K(ret));
|
||||
} else if (OB_FAIL(raw_pos.push_back(pc_param->node_->pos_ - total_delta_len))) {
|
||||
LOG_WARN("failed to push back", K(ret));
|
||||
}
|
||||
}
|
||||
if (OB_FAIL(ret)) {
|
||||
} else if (OB_FAIL(rebuild_new_raw_sql(pc_ctx, temp_store, new_raw_idx,
|
||||
temp_store.count() - new_raw_idx, total_delta_len, new_no_param_sql,
|
||||
new_raw_sql, no_param_sql_pos, new_raw_sql_pos))) {
|
||||
LOG_WARN("failed to rebuild new raw sql", K(ret));
|
||||
} else {
|
||||
int64_t batch_begin_idx = new_raw_idx + param_idx - last_raw_param_idx;
|
||||
if (OB_FAIL(phy_ctx->get_array_param_groups().push_back(ObArrayParamGroup(batch_count,
|
||||
param_count, batch_begin_idx)))) {
|
||||
LOG_WARN("failed to push back", K(ret));
|
||||
} else {
|
||||
total_delta_len += delta_len;
|
||||
can_fold_params = true;
|
||||
last_raw_param_idx = param_idx + param_count * batch_count;
|
||||
new_raw_idx = temp_store.count();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (OB_SUCC(ret) && can_fold_params) {
|
||||
for (int64_t j = last_raw_param_idx; OB_SUCC(ret) && j < pc_ctx.fp_result_.raw_params_.count(); j++) {
|
||||
ObPCParam *pc_param = pc_ctx.fp_result_.raw_params_.at(j);
|
||||
if (OB_ISNULL(pc_param) || OB_ISNULL(pc_param->node_)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("pc_param is null", K(ret), KP(pc_param));
|
||||
} else if (OB_FAIL(temp_store.push_back(pc_param))) {
|
||||
LOG_WARN("failed to push back", K(ret));
|
||||
} else if (OB_FAIL(raw_pos.push_back(pc_param->node_->pos_ - total_delta_len))) {
|
||||
LOG_WARN("failed to push back", K(ret));
|
||||
}
|
||||
}
|
||||
if (OB_SUCC(ret)) {
|
||||
if (OB_FAIL(rebuild_new_raw_sql(pc_ctx, temp_store, new_raw_idx,
|
||||
temp_store.count() - new_raw_idx, total_delta_len, new_no_param_sql,
|
||||
new_raw_sql, no_param_sql_pos, new_raw_sql_pos))) {
|
||||
LOG_WARN("failed to rebuild new raw sql", K(ret));
|
||||
} else if (OB_UNLIKELY(raw_pos.count() != temp_store.count())) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("param is invalid", K(ret));
|
||||
} else {
|
||||
int64_t len = new_no_param_sql.length() - no_param_sql_pos;
|
||||
if (OB_UNLIKELY(len < 0) || OB_UNLIKELY(new_raw_sql_pos + len > buff_len)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected params", K(ret), K(len), K(new_raw_sql_pos));
|
||||
} else if (len > 0) {
|
||||
MEMCPY(buff + new_raw_sql_pos, new_no_param_sql.ptr() + no_param_sql_pos, len);
|
||||
new_raw_sql_pos += len;
|
||||
no_param_sql_pos += len;
|
||||
new_raw_sql.assign_ptr(buff, new_raw_sql_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// handle error.
|
||||
if (ret != OB_SUCCESS) {
|
||||
// 这里边的无论什么报错,都可以被吞掉,只是报错后就不能再做batch优化
|
||||
LOG_TRACE("failed to try fold params for values table", K(ret));
|
||||
phy_ctx->get_array_param_groups().reset();
|
||||
pc_ctx.fp_result_.array_params_.reset();
|
||||
pc_ctx.new_raw_sql_.reset();
|
||||
can_fold_params = false;
|
||||
ret = OB_SUCCESS;
|
||||
} else if (can_fold_params) {
|
||||
fp_result.pc_key_.name_.assign_ptr(new_no_param_sql.ptr(), new_no_param_sql.length());
|
||||
fp_result.raw_params_.reset();
|
||||
fp_result.raw_params_.set_allocator(&allocator);
|
||||
fp_result.raw_params_.set_capacity(temp_store.count());
|
||||
for (int64_t i = 0; i < temp_store.count(); i++) {
|
||||
// checked null before
|
||||
temp_store.at(i)->node_->pos_ = raw_pos.at(i);
|
||||
}
|
||||
if (OB_FAIL(fp_result.raw_params_.assign(temp_store))) {
|
||||
LOG_WARN("fail to assign raw_param", K(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* for choose plan, will resolve all params */
|
||||
int ObValuesTableCompression::resolve_params_for_values_clause(ObPlanCacheCtx &pc_ctx,
|
||||
const stmt::StmtType stmt_type,
|
||||
const ObIArray<NotParamInfo> ¬_param_info,
|
||||
const ObIArray<ObCharsetType> ¶m_charset_type,
|
||||
const ObBitSet<> &neg_param_index,
|
||||
const ObBitSet<> ¬_param_index,
|
||||
const ObBitSet<> &must_be_positive_idx,
|
||||
ParamStore *&ab_params)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
ObSQLSessionInfo *session = pc_ctx.exec_ctx_.get_my_session();
|
||||
ObPhysicalPlanCtx *phy_ctx = pc_ctx.exec_ctx_.get_physical_plan_ctx();
|
||||
ObObjParam obj_param;
|
||||
ObObjParam array_param;
|
||||
void *ptr = NULL;
|
||||
int64_t raw_param_cnt = pc_ctx.fp_result_.raw_params_.count();
|
||||
int64_t raw_idx = 0; // idx in pc_ctx.fp_result_.raw_params_
|
||||
int64_t array_param_idx = 0; // idx in pc_ctx.fp_result_.array_params_
|
||||
int64_t not_param_cnt = 0;
|
||||
bool is_param = false;
|
||||
if (OB_UNLIKELY(!pc_ctx.exec_ctx_.has_dynamic_values_table()) || OB_ISNULL(session) ||
|
||||
OB_ISNULL(phy_ctx) || OB_UNLIKELY(param_charset_type.count() != raw_param_cnt) ||
|
||||
OB_ISNULL(ab_params)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("sql should be mutil stmt", K(ret), KP(session), KP(phy_ctx), K(raw_param_cnt),
|
||||
K(param_charset_type.count()), KP(ab_params));
|
||||
} else if (OB_FAIL(ab_params->reserve(raw_param_cnt))) {
|
||||
LOG_WARN("failed to reserve param num", K(ret));
|
||||
} else {
|
||||
ParamStore &phy_param_store = phy_ctx->get_param_store_for_update();
|
||||
ObIArray<ObArrayParamGroup> &array_param_groups = phy_ctx->get_array_param_groups();
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < array_param_groups.count(); ++i) {
|
||||
int64_t param_num = array_param_groups.at(i).column_count_;
|
||||
int64_t batch_num = array_param_groups.at(i).row_count_;
|
||||
int64_t array_idx = array_param_groups.at(i).start_param_idx_;
|
||||
if (OB_UNLIKELY(array_idx + param_num > raw_param_cnt)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("sql should be mutil stmt", K(ret));
|
||||
}
|
||||
// 1.1 build params before batch group
|
||||
for (; OB_SUCC(ret) && raw_idx < array_idx; raw_idx++) {
|
||||
if (OB_FAIL(ObResolverUtils::resolver_param(pc_ctx, *session, phy_param_store, stmt_type,
|
||||
param_charset_type.at(raw_idx), neg_param_index, not_param_index,
|
||||
must_be_positive_idx, pc_ctx.fp_result_.raw_params_.at(raw_idx), raw_idx,
|
||||
obj_param, is_param))) {
|
||||
LOG_WARN("failed to resolver param", K(ret), K(raw_idx));
|
||||
} else if (!is_param) {
|
||||
not_param_cnt++; // in value clause, which wonn't happen actually
|
||||
} else if (OB_FAIL(ab_params->push_back(obj_param))) {
|
||||
LOG_WARN("fail to push item to array", K(ret), K(raw_idx));
|
||||
}
|
||||
}
|
||||
|
||||
// 1.2 build array_param in batch group
|
||||
for (int64_t j = 0; OB_SUCC(ret) && j < param_num; j++, raw_idx++, array_param_idx++) {
|
||||
ObArrayPCParam *raw_array_param = pc_ctx.fp_result_.array_params_.at(array_param_idx);
|
||||
ObSEArray<ObExprResType, 4> res_types;
|
||||
ObSqlArrayObj *array_param_ptr = ObSqlArrayObj::alloc(pc_ctx.allocator_, batch_num);
|
||||
bool is_same = true;
|
||||
ObExprResType new_res_type;
|
||||
if (OB_ISNULL(array_param_ptr) || OB_ISNULL(raw_array_param)) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
LOG_WARN("failed to allocate memory", K(ret));
|
||||
} else {
|
||||
for (int64_t k = 0; OB_SUCC(ret) && k < batch_num; k++) {
|
||||
if (OB_FAIL(ObResolverUtils::resolver_param(pc_ctx, *session, phy_param_store, stmt_type,
|
||||
param_charset_type.at(raw_idx), neg_param_index, not_param_index,
|
||||
must_be_positive_idx, raw_array_param->at(k), raw_idx,
|
||||
array_param_ptr->data_[k], is_param))) {
|
||||
LOG_WARN("failed to resolver param", K(ret), K(k), K(raw_idx), K(j));
|
||||
} else {
|
||||
const ObObjParam ¶m = array_param_ptr->data_[k];
|
||||
ObExprResType res_type;
|
||||
res_type.set_meta(ObSQLUtils::is_oracle_empty_string(param) ? param.get_param_meta() : param.get_meta());
|
||||
res_type.set_accuracy(param.get_accuracy());
|
||||
res_type.set_result_flag(param.get_result_flag());
|
||||
if (res_type.get_length() == -1) {
|
||||
if (res_type.is_varchar() || res_type.is_nvarchar2()) {
|
||||
res_type.set_length(OB_MAX_ORACLE_VARCHAR_LENGTH);
|
||||
} else if (res_type.is_char() || res_type.is_nchar()) {
|
||||
res_type.set_length(OB_MAX_ORACLE_CHAR_LENGTH_BYTE);
|
||||
}
|
||||
}
|
||||
if (k == 0) {
|
||||
new_res_type = res_type;
|
||||
if (OB_FAIL(res_types.push_back(res_type))) {
|
||||
LOG_WARN("failed to push back", K(ret));
|
||||
}
|
||||
} else if (k > 0 && is_same) {
|
||||
is_same = ObSQLUtils::is_same_type(res_type, res_types.at(0));
|
||||
if (!is_same) {
|
||||
if (OB_FAIL(res_types.push_back(res_type))) {
|
||||
LOG_WARN("failed to push back", K(ret));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (OB_FAIL(res_types.push_back(res_type))) {
|
||||
LOG_WARN("failed to push back", K(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 推导类型 */
|
||||
if (OB_SUCC(ret) && !is_same) {
|
||||
new_res_type.reset();
|
||||
ObExprVersion dummy_op(pc_ctx.allocator_);
|
||||
const ObLengthSemantics length_semantics = session->get_actual_nls_length_semantics();
|
||||
ObCollationType coll_type = CS_TYPE_INVALID;
|
||||
if (OB_FAIL(session->get_collation_connection(coll_type))) {
|
||||
LOG_WARN("fail to get_collation_connection", K(ret));
|
||||
} else if (OB_FAIL(dummy_op.aggregate_result_type_for_merge(new_res_type,
|
||||
&res_types.at(0),
|
||||
res_types.count(),
|
||||
coll_type,
|
||||
false,
|
||||
length_semantics,
|
||||
session))) {
|
||||
LOG_WARN("failed to aggregate result type for merge", K(ret));
|
||||
}
|
||||
}
|
||||
if (OB_SUCC(ret)) {
|
||||
array_param.reset();
|
||||
array_param_ptr->element_.set_meta_type(new_res_type.get_obj_meta());
|
||||
array_param_ptr->element_.set_accuracy(new_res_type.get_accuracy());
|
||||
array_param.set_extend(reinterpret_cast<int64_t>(array_param_ptr), T_EXT_SQL_ARRAY);
|
||||
array_param.set_param_meta();
|
||||
array_param.get_param_flag().is_batch_parameter_ = true;
|
||||
if (OB_FAIL(ab_params->push_back(array_param))) {
|
||||
LOG_WARN("failed to push back param", K(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; OB_SUCC(ret) && raw_idx < raw_param_cnt; raw_idx++) {
|
||||
if (OB_FAIL(ObResolverUtils::resolver_param(pc_ctx, *session, phy_param_store, stmt_type,
|
||||
param_charset_type.at(raw_idx), neg_param_index, not_param_index,
|
||||
must_be_positive_idx, pc_ctx.fp_result_.raw_params_.at(raw_idx), raw_idx,
|
||||
obj_param, is_param))) {
|
||||
LOG_WARN("failed to resolver param", K(ret), K(raw_idx));
|
||||
} else if (!is_param) {
|
||||
not_param_cnt++;
|
||||
} else if (OB_FAIL(ab_params->push_back(obj_param))) {
|
||||
LOG_WARN("fail to push item to array", K(ret), K(raw_idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* after handle parser, only resolve array params */
|
||||
int ObValuesTableCompression::resolve_params_for_values_clause(ObPlanCacheCtx &pc_ctx)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
const ObBitSet<> bit_set_dummy;
|
||||
ObSQLSessionInfo *session = pc_ctx.exec_ctx_.get_my_session();
|
||||
ObPhysicalPlanCtx *phy_ctx = pc_ctx.exec_ctx_.get_physical_plan_ctx();
|
||||
ObObjParam obj_param;
|
||||
ObObjParam array_param;
|
||||
int64_t raw_param_cnt = pc_ctx.fp_result_.raw_params_.count();
|
||||
int64_t raw_idx = 0; // idx in pc_ctx.fp_result_.raw_params_
|
||||
int64_t array_param_idx = 0; // idx in pc_ctx.fp_result_.array_params_
|
||||
bool is_param = false;
|
||||
const ObIArray<ObCharsetType> ¶m_charset_type = pc_ctx.param_charset_type_;
|
||||
if (OB_UNLIKELY(!pc_ctx.exec_ctx_.has_dynamic_values_table()) || OB_ISNULL(session) ||
|
||||
OB_ISNULL(phy_ctx) || OB_UNLIKELY(param_charset_type.count() != raw_param_cnt)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("sql should be mutil stmt", K(ret), KP(session), KP(phy_ctx), K(raw_param_cnt),
|
||||
K(param_charset_type.count()));
|
||||
} else {
|
||||
ParamStore &phy_param_store = phy_ctx->get_param_store_for_update();
|
||||
ObIArray<ObArrayParamGroup> &array_param_groups = phy_ctx->get_array_param_groups();
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < array_param_groups.count(); ++i) {
|
||||
int64_t param_num = array_param_groups.at(i).column_count_;
|
||||
int64_t batch_num = array_param_groups.at(i).row_count_;
|
||||
int64_t raw_idx = array_param_groups.at(i).start_param_idx_;
|
||||
if (OB_UNLIKELY(raw_idx + param_num > raw_param_cnt) ||
|
||||
OB_UNLIKELY(raw_idx + param_num > phy_param_store.count())) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("sql should be mutil stmt", K(ret));
|
||||
}
|
||||
for (int64_t j = 0; OB_SUCC(ret) && j < param_num; j++, raw_idx++, array_param_idx++) {
|
||||
ObArrayPCParam *raw_array_param = pc_ctx.fp_result_.array_params_.at(array_param_idx);
|
||||
ObSEArray<ObExprResType, 4> res_types;
|
||||
ObSqlArrayObj *array_param_ptr = ObSqlArrayObj::alloc(pc_ctx.allocator_, batch_num);
|
||||
bool is_same = true;
|
||||
ObExprResType new_res_type;
|
||||
if (OB_ISNULL(array_param_ptr) || OB_ISNULL(raw_array_param)) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
LOG_WARN("failed to allocate memory", K(ret));
|
||||
} else {
|
||||
for (int64_t k = 0; OB_SUCC(ret) && k < batch_num; k++) {
|
||||
if (OB_FAIL(ObResolverUtils::resolver_param(pc_ctx, *session, phy_param_store, stmt::T_SELECT,
|
||||
param_charset_type.at(raw_idx), bit_set_dummy, bit_set_dummy,
|
||||
bit_set_dummy, raw_array_param->at(k), raw_idx,
|
||||
array_param_ptr->data_[k], is_param))) {
|
||||
LOG_WARN("failed to resolver param", K(ret), K(k), K(raw_idx), K(j));
|
||||
} else {
|
||||
const ObObjParam ¶m = array_param_ptr->data_[k];
|
||||
ObExprResType res_type;
|
||||
res_type.set_meta(ObSQLUtils::is_oracle_empty_string(param) ? param.get_param_meta() : param.get_meta());
|
||||
res_type.set_accuracy(param.get_accuracy());
|
||||
res_type.set_result_flag(param.get_result_flag());
|
||||
if (res_type.get_length() == -1) {
|
||||
if (res_type.is_varchar() || res_type.is_nvarchar2()) {
|
||||
res_type.set_length(OB_MAX_ORACLE_VARCHAR_LENGTH);
|
||||
} else if (res_type.is_char() || res_type.is_nchar()) {
|
||||
res_type.set_length(OB_MAX_ORACLE_CHAR_LENGTH_BYTE);
|
||||
}
|
||||
}
|
||||
if (k == 0) {
|
||||
new_res_type = res_type;
|
||||
if (OB_FAIL(res_types.push_back(res_type))) {
|
||||
LOG_WARN("failed to push back", K(ret));
|
||||
}
|
||||
} else if (k > 0 && is_same) {
|
||||
is_same = ObSQLUtils::is_same_type(res_type, res_types.at(0));
|
||||
if (!is_same) {
|
||||
if (OB_FAIL(res_types.push_back(res_type))) {
|
||||
LOG_WARN("failed to push back", K(ret));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (OB_FAIL(res_types.push_back(res_type))) {
|
||||
LOG_WARN("failed to push back", K(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 推导类型 */
|
||||
if (OB_SUCC(ret) && !is_same) {
|
||||
new_res_type.reset();
|
||||
ObExprVersion dummy_op(pc_ctx.allocator_);
|
||||
const ObLengthSemantics length_semantics = session->get_actual_nls_length_semantics();
|
||||
ObCollationType coll_type = CS_TYPE_INVALID;
|
||||
if (OB_FAIL(session->get_collation_connection(coll_type))) {
|
||||
LOG_WARN("fail to get_collation_connection", K(ret));
|
||||
} else if (OB_FAIL(dummy_op.aggregate_result_type_for_merge(new_res_type,
|
||||
&res_types.at(0),
|
||||
res_types.count(),
|
||||
coll_type,
|
||||
false,
|
||||
length_semantics,
|
||||
session))) {
|
||||
LOG_WARN("failed to aggregate result type for merge", K(ret));
|
||||
} else {
|
||||
LOG_TRACE("get result type", K(new_res_type), K(res_types));
|
||||
}
|
||||
}
|
||||
if (OB_SUCC(ret)) {
|
||||
array_param.reset();
|
||||
array_param_ptr->element_.set_meta_type(new_res_type.get_obj_meta());
|
||||
array_param_ptr->element_.set_accuracy(new_res_type.get_accuracy());
|
||||
array_param.set_extend(reinterpret_cast<int64_t>(array_param_ptr), T_EXT_SQL_ARRAY);
|
||||
array_param.set_param_meta();
|
||||
array_param.get_param_flag().is_batch_parameter_ = true;
|
||||
phy_param_store.at(raw_idx) = array_param;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ObValuesTableCompression::skip_space(ObRawSql &raw_sql)
|
||||
{
|
||||
int64_t space_len = 0;
|
||||
bool is_space = true;
|
||||
while (!raw_sql.search_end_ && is_space && raw_sql.cur_pos_ < raw_sql.raw_sql_len_) {
|
||||
if (is_mysql_space(raw_sql.raw_sql_[raw_sql.cur_pos_])) {
|
||||
raw_sql.scan(1);
|
||||
} else {
|
||||
is_space = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ObValuesTableCompression::skip_row_constructor(ObRawSql &raw_sql)
|
||||
{
|
||||
bool b_ret = false;
|
||||
int64_t space_len = 0;
|
||||
if (!raw_sql.search_end_ && 0 == raw_sql.strncasecmp(raw_sql.cur_pos_, "row", 3)) {
|
||||
raw_sql.scan(3);
|
||||
skip_space(raw_sql);
|
||||
b_ret = true;
|
||||
}
|
||||
return b_ret;
|
||||
}
|
||||
|
||||
/* only row(?,?,?) is valid */
|
||||
void ObValuesTableCompression::get_one_row_str(ObRawSql &no_param_sql,
|
||||
int64_t ¶m_count,
|
||||
int64_t &end_pos,
|
||||
bool &is_valid)
|
||||
{
|
||||
enum ROW_STATE {
|
||||
START_STATE = 0,
|
||||
LEFT_PAR_STATE, // "("
|
||||
PARS_MATCH, // ")"
|
||||
UNEXPECTED_STATE
|
||||
};
|
||||
ROW_STATE row_state = START_STATE;
|
||||
int left_count = 0;
|
||||
int comma_count = 0;
|
||||
bool need_break = false;
|
||||
int64_t curr_pos = 0;
|
||||
is_valid = false;
|
||||
param_count = 0;
|
||||
end_pos = 0;
|
||||
skip_space(no_param_sql);
|
||||
if (no_param_sql.is_search_end() || !skip_row_constructor(no_param_sql)) {
|
||||
/* do nothing */
|
||||
} else {
|
||||
while (!need_break && !no_param_sql.is_search_end()) {
|
||||
skip_space(no_param_sql);
|
||||
char ch = no_param_sql.char_at(no_param_sql.cur_pos_);
|
||||
curr_pos = no_param_sql.cur_pos_;
|
||||
no_param_sql.scan(1);
|
||||
/* state machine */
|
||||
switch (row_state) {
|
||||
case START_STATE:
|
||||
if ('(' == ch) {
|
||||
row_state = LEFT_PAR_STATE;
|
||||
left_count++;
|
||||
} else {
|
||||
row_state = UNEXPECTED_STATE;
|
||||
}
|
||||
break;
|
||||
case LEFT_PAR_STATE:
|
||||
if (')' == ch) {
|
||||
left_count--;
|
||||
if (0 == left_count) {
|
||||
row_state = PARS_MATCH;
|
||||
end_pos = curr_pos;
|
||||
}
|
||||
} else if ('(' == ch) {
|
||||
left_count++;
|
||||
} else if ('?' == ch) {
|
||||
param_count++;
|
||||
} else if (',' == ch && comma_count + 1 == param_count) {
|
||||
comma_count++;
|
||||
} else {
|
||||
row_state = UNEXPECTED_STATE;
|
||||
}
|
||||
break;
|
||||
case PARS_MATCH:
|
||||
if (',' != ch) {
|
||||
no_param_sql.search_end_ = true;
|
||||
}
|
||||
need_break = true;
|
||||
break;
|
||||
case UNEXPECTED_STATE:
|
||||
need_break = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (PARS_MATCH == row_state) {
|
||||
if (param_count > 0 && param_count == comma_count + 1) {
|
||||
is_valid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ObValuesTableCompression::parser_values_row_str(ObIAllocator &allocator,
|
||||
const ObString &no_param_sql,
|
||||
const int64_t values_token_pos,
|
||||
ObString &new_no_param_sql,
|
||||
int64_t &old_pos,
|
||||
int64_t &new_pos,
|
||||
int64_t &row_count,
|
||||
int64_t ¶m_count,
|
||||
int64_t &delta_length,
|
||||
bool &can_batch_opt)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
int64_t no_param_sql_len = no_param_sql.length();
|
||||
ObRawSql raw_sql;
|
||||
raw_sql.init(no_param_sql.ptr(), no_param_sql_len);
|
||||
raw_sql.cur_pos_ = values_token_pos;
|
||||
int64_t new_sql_len = 0;
|
||||
int64_t cur_param_count = 0;
|
||||
int64_t end_pos = 0;
|
||||
int64_t first_sql_end_pos = 0;
|
||||
bool is_first = true;
|
||||
bool is_valid = true;
|
||||
row_count = 0;
|
||||
param_count = 0;
|
||||
delta_length = 0;
|
||||
can_batch_opt = false;
|
||||
if (0 == raw_sql.strncasecmp(raw_sql.cur_pos_, "values", 6)) {
|
||||
raw_sql.scan(6);
|
||||
while (OB_SUCC(ret) && is_valid && !raw_sql.is_search_end()) {
|
||||
get_one_row_str(raw_sql, cur_param_count, end_pos, is_valid);
|
||||
if (!is_valid) {
|
||||
} else if (is_first) {
|
||||
param_count = cur_param_count;
|
||||
first_sql_end_pos = end_pos;
|
||||
is_first = false;
|
||||
} else if (cur_param_count != param_count) {
|
||||
LOG_WARN("should not be here", K(ret), K(cur_param_count), K(param_count));
|
||||
}
|
||||
row_count++;
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret) && is_valid && row_count > 1) {
|
||||
char *buffer = NULL;
|
||||
if (OB_ISNULL(buffer = static_cast<char*>(allocator.alloc(no_param_sql_len)))) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
LOG_WARN("fail to alloc memory", K(ret), K(no_param_sql_len));
|
||||
} else {
|
||||
// init
|
||||
int64_t length = new_pos;
|
||||
MEMCPY(buffer, new_no_param_sql.ptr(), length);
|
||||
new_sql_len += length;
|
||||
|
||||
length = first_sql_end_pos + 1 - old_pos;
|
||||
MEMCPY(buffer + new_pos, no_param_sql.ptr() + old_pos, length);
|
||||
new_sql_len += length;
|
||||
new_pos += length;
|
||||
old_pos = end_pos + 1;
|
||||
|
||||
length = no_param_sql_len - old_pos;
|
||||
MEMCPY(buffer + new_pos, no_param_sql.ptr() + old_pos, length);
|
||||
new_sql_len += length;
|
||||
|
||||
delta_length = end_pos - first_sql_end_pos;
|
||||
new_no_param_sql.assign_ptr(buffer, new_sql_len);
|
||||
can_batch_opt = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
92
src/sql/plan_cache/ob_values_table_compression.h
Normal file
92
src/sql/plan_cache/ob_values_table_compression.h
Normal file
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef OCEANBASE_SQL_PLAN_CACHE_OB_VALUES_TABLE_COMPRESSION_
|
||||
#define OCEANBASE_SQL_PLAN_CACHE_OB_VALUES_TABLE_COMPRESSION_
|
||||
|
||||
#include "sql/parser/ob_parser.h"
|
||||
#include "lib/string/ob_string.h"
|
||||
|
||||
namespace oceanbase
|
||||
{
|
||||
namespace sql
|
||||
{
|
||||
class ObPlanCacheCtx;
|
||||
struct ObRawSql;
|
||||
class ObFastParserResult;
|
||||
|
||||
// values clause folding params utils class
|
||||
class ObValuesTableCompression {
|
||||
public:
|
||||
static int try_batch_exec_params(common::ObIAllocator &allocator,
|
||||
ObPlanCacheCtx &pc_ctx,
|
||||
ObSQLSessionInfo &session_info,
|
||||
ObFastParserResult &fp_result);
|
||||
// for resolve params in fast parser to match plan set
|
||||
static int resolve_params_for_values_clause(ObPlanCacheCtx &pc_ctx,
|
||||
const stmt::StmtType stmt_type,
|
||||
const common::ObIArray<NotParamInfo> ¬_param_info,
|
||||
const common::ObIArray<ObCharsetType> ¶m_charset_type,
|
||||
const ObBitSet<> &neg_param_index,
|
||||
const ObBitSet<> ¬_param_index,
|
||||
const ObBitSet<> &must_be_positive_idx,
|
||||
ParamStore *&ab_params);
|
||||
// for resolve array params after handler_parser
|
||||
static int resolve_params_for_values_clause(ObPlanCacheCtx &pc_ctx);
|
||||
static int parser_values_row_str(common::ObIAllocator &allocator,
|
||||
const common::ObString &no_param_sql,
|
||||
const int64_t values_token_pos,
|
||||
common::ObString &new_no_param_sql,
|
||||
int64_t &old_end_pos,
|
||||
int64_t &new_end_pos,
|
||||
int64_t &row_count,
|
||||
int64_t ¶m_count,
|
||||
int64_t &delta_length,
|
||||
bool &can_batch_opt);
|
||||
private:
|
||||
static void match_one_state(const char *&p,
|
||||
const char *p_end,
|
||||
const ObParser::State next_state,
|
||||
ObParser::State &state);
|
||||
static bool is_support_compress_values_table(const common::ObString &stmt);
|
||||
static int add_raw_array_params(common::ObIAllocator &allocator,
|
||||
ObPlanCacheCtx &pc_ctx,
|
||||
const ObFastParserResult &fp_result,
|
||||
const int64_t begin_param,
|
||||
const int64_t row_count,
|
||||
const int64_t param_count);
|
||||
static int rebuild_new_raw_sql(ObPlanCacheCtx &pc_ctx,
|
||||
const common::ObIArray<ObPCParam*> &raw_params,
|
||||
const int64_t begin_idx,
|
||||
const int64_t param_cnt,
|
||||
const int64_t delta_length,
|
||||
const common::ObString &no_param_sql,
|
||||
common::ObString &new_raw_sql,
|
||||
int64_t &no_param_sql_pos,
|
||||
int64_t &new_raw_pos);
|
||||
static bool is_mysql_space(char ch) {
|
||||
return ch != INVALID_CHAR && SPACE_FLAGS[static_cast<uint8_t>(ch)];
|
||||
}
|
||||
static void skip_space(ObRawSql &raw_sql);
|
||||
static bool skip_row_constructor(ObRawSql &raw_sql);
|
||||
static void get_one_row_str(ObRawSql &no_param_sql,
|
||||
int64_t ¶m_count,
|
||||
int64_t &end_pos,
|
||||
bool &is_valid);
|
||||
private:
|
||||
static const char *lower_[ObParser::S_MAX];
|
||||
static const char *upper_[ObParser::S_MAX];
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* _OB_VALUES_TABLE_COMPRESSION_H */
|
||||
Reference in New Issue
Block a user