fix: enable inlist rewrite for prepare stmt with question mark

This commit is contained in:
PatZhuang 2024-11-25 03:45:34 +00:00 committed by ob-robot
parent 21acb7b3ec
commit 3a69729b35
2 changed files with 66 additions and 53 deletions

View File

@ -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 &params = 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,

View File

@ -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_;