fix: enable inlist rewrite for prepare stmt with question mark
This commit is contained in:
parent
21acb7b3ec
commit
3a69729b35
@ -36,9 +36,14 @@ int ObInListResolver::resolve_inlist(ObInListInfo &inlist_info)
|
||||
LOG_WARN("got NULL ptr", K(ret), KP(list_node), KP(cur_resolver_));
|
||||
} else {
|
||||
ObResolverParams ¶ms = cur_resolver_->params_;
|
||||
if (OB_FAIL(resolve_values_table_from_inlist(list_node, column_cnt, row_cnt,
|
||||
inlist_info.is_question_mark_, params.param_list_,
|
||||
params.session_info_, params.allocator_,
|
||||
if (OB_FAIL(resolve_values_table_from_inlist(list_node,
|
||||
column_cnt,
|
||||
row_cnt,
|
||||
inlist_info.is_question_mark_,
|
||||
params.is_prepare_stage_,
|
||||
params.param_list_,
|
||||
params.session_info_,
|
||||
params.allocator_,
|
||||
table_def))) {
|
||||
LOG_WARN("failed to resolve values table from inlist", K(ret));
|
||||
} else if (OB_FAIL(resolve_subquery_from_values_table(params.stmt_factory_,
|
||||
@ -60,6 +65,7 @@ int ObInListResolver::resolve_values_table_from_inlist(const ParseNode *in_list,
|
||||
const int64_t column_cnt,
|
||||
const int64_t row_cnt,
|
||||
const bool is_question_mark,
|
||||
const bool is_prepare_stage,
|
||||
const ParamStore *param_store,
|
||||
ObSQLSessionInfo *session_info,
|
||||
ObIAllocator *allocator,
|
||||
@ -67,8 +73,10 @@ int ObInListResolver::resolve_values_table_from_inlist(const ParseNode *in_list,
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
char *table_buf = NULL;
|
||||
ObValuesTableDef::TableAccessType access_type = is_question_mark ?
|
||||
ObValuesTableDef::ACCESS_PARAM : ObValuesTableDef::ACCESS_OBJ;
|
||||
// we treat question marks in prepare stmt as objs instead of params
|
||||
ObValuesTableDef::TableAccessType access_type = is_question_mark && !is_prepare_stage
|
||||
? ObValuesTableDef::ACCESS_PARAM
|
||||
: ObValuesTableDef::ACCESS_OBJ;
|
||||
if (OB_ISNULL(allocator) || OB_ISNULL(session_info) || OB_ISNULL(in_list)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("got unexpected NULL ptr", K(ret));
|
||||
@ -92,7 +100,7 @@ int ObInListResolver::resolve_values_table_from_inlist(const ParseNode *in_list,
|
||||
LOG_WARN("failed to resolve access param values table", K(ret));
|
||||
} else if (ObValuesTableDef::ACCESS_OBJ == access_type &&
|
||||
OB_FAIL(resolve_access_obj_values_table(*in_list, column_cnt, row_cnt, session_info,
|
||||
allocator, *table_def))) {
|
||||
allocator, is_prepare_stage, *table_def))) {
|
||||
LOG_WARN("failed to resolve access obj values table", K(ret));
|
||||
} else if (OB_FAIL(cur_resolver_->estimate_values_table_stats(*table_def))) {
|
||||
LOG_WARN("failed to estimate values table stats", K(ret));
|
||||
@ -168,6 +176,7 @@ int ObInListResolver::check_inlist_rewrite_enable(const ParseNode &in_list,
|
||||
is_enable = false;
|
||||
int64_t threshold = INT64_MAX;
|
||||
uint64_t optimizer_features_enable_version = 0;
|
||||
bool is_prepare_stmt = false;
|
||||
// 1. check basic requests
|
||||
if (OB_ISNULL(session_info)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
@ -177,12 +186,11 @@ int ObInListResolver::check_inlist_rewrite_enable(const ParseNode &in_list,
|
||||
|| (T_OP_IN != op_type && T_OP_NOT_IN != op_type)
|
||||
|| T_EXPR_LIST != in_list.type_
|
||||
|| is_need_print
|
||||
|| session_info->is_varparams_sql_prepare()
|
||||
|| (NULL != stmt
|
||||
&& stmt->is_select_stmt()
|
||||
&& static_cast<const ObSelectStmt *>(stmt)->is_hierarchical_query())) {
|
||||
LOG_TRACE("no need rewrite inlist", K(is_root_condition), K(scope), K(in_list.type_),
|
||||
K(op_type), K(is_need_print), K(session_info->is_varparams_sql_prepare()));
|
||||
LOG_TRACE("no need rewrite inlist",
|
||||
K(is_root_condition), K(scope), K(in_list.type_), K(op_type), K(is_need_print));
|
||||
} else {
|
||||
if (NULL == stmt) {
|
||||
if (OB_FAIL(session_info->get_optimizer_features_enable_version(optimizer_features_enable_version))) {
|
||||
@ -195,6 +203,7 @@ int ObInListResolver::check_inlist_rewrite_enable(const ParseNode &in_list,
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected null", K(ret));
|
||||
} else {
|
||||
is_prepare_stmt = stmt->get_query_ctx()->is_prepare_stmt();
|
||||
threshold = session_info->get_inlist_rewrite_threshold();
|
||||
const ObGlobalHint &global_hint = stmt->get_query_ctx()->get_global_hint();
|
||||
if (OB_FAIL(global_hint.opt_params_.get_integer_opt_param(
|
||||
@ -240,54 +249,45 @@ int ObInListResolver::check_inlist_rewrite_enable(const ParseNode &in_list,
|
||||
share::SYS_VAR_COLLATION_SERVER, server_collation))) {
|
||||
LOG_WARN("get sys variables failed", K(ret));
|
||||
} else {
|
||||
for (int64_t j = 0; OB_SUCC(ret) && is_enable && j < column_cnt; j++) {
|
||||
const ParseNode *node = column_cnt == 1 ? in_list.children_[0] :
|
||||
in_list.children_[0]->children_[j];
|
||||
DistinctObjMeta param_type;
|
||||
// know this inlist is question mark or const
|
||||
if (j == 0) {
|
||||
if (OB_ISNULL(node)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected param", K(ret));
|
||||
} else {
|
||||
is_question_mark = T_QUESTIONMARK == node->type_;
|
||||
}
|
||||
}
|
||||
if (OB_FAIL(ret)) {
|
||||
} else if (OB_FAIL(get_const_node_types(node, param_store, is_question_mark,
|
||||
connect_collation, nchar_collation, static_cast<ObCollationType>(server_collation), enable_decimal_int, alloc,
|
||||
param_type, is_enable))) {
|
||||
LOG_WARN("failed to got const node types", K(ret));
|
||||
} else if (is_enable) {
|
||||
if (lib::is_oracle_mode() && ObCharType == param_type.obj_type_) {
|
||||
// in oracle mode, inlist to values table rewrite may cast char types to varchar2
|
||||
// but comparison behaviors for chars and varchar2s are different for trailing spaces
|
||||
// which will lead to unexpect comparison result
|
||||
is_enable = false;
|
||||
} else
|
||||
if (ob_is_enum_or_set_type(param_type.obj_type_) ||
|
||||
is_lob_locator(param_type.obj_type_)) {
|
||||
is_enable = false;
|
||||
} else if (OB_FAIL(param_types.push_back(param_type))) {
|
||||
LOG_WARN("failed to push back", K(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int64_t i = 1; OB_SUCC(ret) && is_enable && i < row_cnt; i++) {
|
||||
for (int64_t j = 0; OB_SUCC(ret) && is_enable && j < column_cnt; j++) {
|
||||
for (int64_t j = 0; OB_SUCC(ret) && is_enable && j < column_cnt; ++j) {
|
||||
DistinctObjMeta param_type_prev;
|
||||
for (int64_t i = 0; OB_SUCC(ret) && is_enable && i < row_cnt; ++i) {
|
||||
if (OB_UNLIKELY(column_cnt > 1 && in_list.children_[i]->num_child_ != column_cnt)) {
|
||||
is_enable = false; /* delay return error code */
|
||||
} else {
|
||||
const ParseNode *node = column_cnt == 1 ? in_list.children_[i] :
|
||||
in_list.children_[i]->children_[j];
|
||||
DistinctObjMeta param_type;
|
||||
if (OB_FAIL(get_const_node_types(node, param_store, is_question_mark,
|
||||
connect_collation, nchar_collation, static_cast<ObCollationType>(server_collation), enable_decimal_int, alloc,
|
||||
param_type, is_enable))) {
|
||||
DistinctObjMeta param_type_cur;
|
||||
const ParseNode *node = column_cnt == 1 ? in_list.children_[i]
|
||||
: in_list.children_[i]->children_[j];
|
||||
if (OB_ISNULL(node)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected param", K(ret));
|
||||
} else if (FALSE_IT(is_question_mark = T_QUESTIONMARK == node->type_)) {
|
||||
} else if (is_prepare_stmt && is_question_mark) {
|
||||
// skip type matching for question marks in prepare stmt, because they have no type
|
||||
} else if (OB_FAIL(get_const_node_types(node,
|
||||
param_store,
|
||||
is_question_mark,
|
||||
connect_collation,
|
||||
nchar_collation,
|
||||
static_cast<ObCollationType>(server_collation),
|
||||
enable_decimal_int,
|
||||
alloc,
|
||||
param_type_cur,
|
||||
is_enable))) {
|
||||
LOG_WARN("failed to got const node types", K(ret));
|
||||
} else if (is_enable && param_type == param_types.at(j)) {
|
||||
/*is same type*/
|
||||
} else if (!is_enable) {
|
||||
} else if (ObMaxType == param_type_prev.obj_type_) {
|
||||
param_type_prev = param_type_cur;
|
||||
if (lib::is_oracle_mode() && ObCharType == param_type_cur.obj_type_) {
|
||||
// in oracle mode, inlist to values table rewrite may cast char types to varchar2
|
||||
// but comparison behaviors for chars and varchar2s are different for trailing spaces
|
||||
// which will lead to unexpect comparison result
|
||||
is_enable = false;
|
||||
} else if (ob_is_enum_or_set_type(param_type_cur.obj_type_)
|
||||
|| is_lob_locator(param_type_cur.obj_type_)) {
|
||||
is_enable = false;
|
||||
}
|
||||
} else if (param_type_prev == param_type_cur) {
|
||||
} else {
|
||||
is_enable = false;
|
||||
}
|
||||
@ -401,6 +401,7 @@ int ObInListResolver::resolve_access_obj_values_table(const ParseNode &in_list,
|
||||
const int64_t row_cnt,
|
||||
ObSQLSessionInfo *session_info,
|
||||
ObIAllocator *allocator,
|
||||
const bool is_prepare_stage,
|
||||
ObValuesTableDef &table_def)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
@ -449,8 +450,18 @@ int ObInListResolver::resolve_access_obj_values_table(const ParseNode &in_list,
|
||||
}
|
||||
for (int64_t j = 0; OB_SUCC(ret) && j < column_cnt; j++) {
|
||||
const ParseNode *element = column_cnt == 1 ? row_node : row_node->children_[j];
|
||||
ParseNode pseudo_char_node = {.type_ = T_CHAR, .str_value_ = NULL, .str_len_ = 0};
|
||||
ObObjParam obj_param;
|
||||
ObExprResType res_type;
|
||||
if (is_prepare_stage && T_QUESTIONMARK == element->type_) {
|
||||
// In prepare stage, we resolve question marks as an empty char node.
|
||||
// This is just for result type aggregation in prepare stage only.
|
||||
// In execution time of ps protocol, the question marks will be resolved with real values.
|
||||
pseudo_char_node.type_ = T_CHAR;
|
||||
pseudo_char_node.str_len_ = 0;
|
||||
pseudo_char_node.str_value_ = NULL;
|
||||
element = &pseudo_char_node;
|
||||
}
|
||||
if (OB_FAIL(ObResolverUtils::resolve_const(element, stmt_type, *allocator, coll_type,
|
||||
nchar_collation, timezone_info, obj_param, is_paramlize,
|
||||
literal_prefix, length_semantics,
|
||||
|
@ -59,6 +59,7 @@ private:
|
||||
const int64_t column_cnt,
|
||||
const int64_t row_cnt,
|
||||
const bool is_question_mark,
|
||||
const bool is_prepare_stmt,
|
||||
const ParamStore *param_store,
|
||||
ObSQLSessionInfo *session_info,
|
||||
ObIAllocator *allocator,
|
||||
@ -94,6 +95,7 @@ private:
|
||||
const int64_t row_cnt,
|
||||
ObSQLSessionInfo *session_info,
|
||||
ObIAllocator *allocator,
|
||||
const bool is_prepare_stage,
|
||||
ObValuesTableDef &table_def);
|
||||
private:
|
||||
ObDMLResolver *cur_resolver_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user