From 78a2108dc655eeea2c8b2fa0344a034e1b873839 Mon Sep 17 00:00:00 2001 From: hy-guo Date: Thu, 22 Aug 2024 04:18:02 +0000 Subject: [PATCH] [CP] fix select * in exists --- src/sql/parser/sql_parser_mysql_mode.y | 4 --- src/sql/resolver/dml/ob_dml_resolver.cpp | 1 + src/sql/resolver/dml/ob_select_resolver.cpp | 30 +++++++++++++++++-- .../resolver/dml/ob_view_table_resolver.cpp | 1 + src/sql/resolver/expr/ob_expr_info_flag.h | 4 ++- .../expr/ob_raw_expr_info_extractor.cpp | 6 ++++ .../expr/ob_raw_expr_resolver_impl.cpp | 7 ++++- 7 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/sql/parser/sql_parser_mysql_mode.y b/src/sql/parser/sql_parser_mysql_mode.y index 1b6a44557d..058382a46e 100644 --- a/src/sql/parser/sql_parser_mysql_mode.y +++ b/src/sql/parser/sql_parser_mysql_mode.y @@ -1673,10 +1673,6 @@ simple_expr collation %prec NEG } | EXISTS select_with_parens { - /* mysql 允许 select * from dual 出现在 exists 中, 此处更改 from dual 的 select list 为常量 1 */ - if (NULL == $2->children_[PARSE_SELECT_FROM]) { - $2->value_ = 2; - } malloc_non_terminal_node($$, result->malloc_pool_, T_OP_EXISTS, 1, $2); } | MATCH '(' column_list ')' AGAINST '(' search_expr opt_mode_flag ')' diff --git a/src/sql/resolver/dml/ob_dml_resolver.cpp b/src/sql/resolver/dml/ob_dml_resolver.cpp index f958979997..c523a178de 100755 --- a/src/sql/resolver/dml/ob_dml_resolver.cpp +++ b/src/sql/resolver/dml/ob_dml_resolver.cpp @@ -7455,6 +7455,7 @@ int ObDMLResolver::resolve_subquery_info(const ObIArray &subquer subquery_resolver.set_current_level(current_level_ + 1); subquery_resolver.set_current_view_level(current_view_level_); subquery_resolver.set_parent_namespace_resolver(this); + subquery_resolver.set_in_exists_subquery(info.parents_expr_info_.has_member(IS_EXISTS)); set_query_ref_exec_params(info.ref_expr_ == NULL ? NULL : &info.ref_expr_->get_exec_params()); if (OB_FAIL(add_cte_table_to_children(subquery_resolver))) { LOG_WARN("add CTE table to children failed", K(ret)); diff --git a/src/sql/resolver/dml/ob_select_resolver.cpp b/src/sql/resolver/dml/ob_select_resolver.cpp index d88d32526a..6509f47fcc 100644 --- a/src/sql/resolver/dml/ob_select_resolver.cpp +++ b/src/sql/resolver/dml/ob_select_resolver.cpp @@ -53,6 +53,7 @@ ObSelectResolver::ObSelectResolver(ObResolverParams ¶ms) has_top_limit_(false), in_set_query_(false), is_sub_stmt_(false), + in_exists_subquery_(false), standard_group_checker_(), transpose_item_(NULL), is_left_child_(false), @@ -1312,8 +1313,6 @@ int ObSelectResolver::resolve_normal_query(const ParseNode &parse_tree) OB_NOT_NULL(session_info_), OB_NOT_NULL(select_stmt->get_query_ctx())); - set_in_exists_subquery(2 == parse_tree.value_); - /** * @muhang.zb * 定义了一个cte,无论最终是否在主句使用,都必须要进行解析 @@ -2963,6 +2962,8 @@ int ObSelectResolver::resolve_star(const ParseNode *node) SelectItem select_item; if (lib::is_mysql_mode()) { ObConstRawExpr *c_expr = NULL; + select_item.alias_name_ = "1"; + select_item.expr_name_ = "1"; if (!is_in_exists_subquery()) { ret = OB_ERR_NO_TABLES_USED; LOG_WARN("No tables used"); @@ -3024,7 +3025,29 @@ int ObSelectResolver::resolve_star(const ParseNode *node) bool is_column_name_equal = false; const TableItem* tab_item = NULL; ObNameCaseMode case_mode = OB_NAME_CASE_INVALID; - if (OB_FAIL(session_info_->get_name_case_mode(case_mode))) { + if (is_in_exists_subquery()) { + // Oracle and MySQL support use any.* as EXISTS subquery select item. + // Consider SQL: SELECT ... FROM T1 WHERE EXISTS (SELECT T3.* FROM T2); + // Even if T3 does not exist, this SQL statement can still be executed + // successfully. + // Here, we just simply resolve any.* in exists subquery as 1. + SelectItem select_item; + ObConstRawExpr *c_expr = NULL; + select_item.alias_name_ = "1"; + select_item.expr_name_ = "1"; + if (lib::is_oracle_mode() && + OB_FAIL(ObRawExprUtils::build_const_number_expr(*params_.expr_factory_, ObNumberType, + number::ObNumber::get_positive_one(), c_expr))) { + LOG_WARN("failed to build const number 1 expr", K(ret)); + } else if (!lib::is_oracle_mode() && + OB_FAIL(ObRawExprUtils::build_const_int_expr(*params_.expr_factory_, + ObIntType, 1, c_expr))) { + LOG_WARN("failed to build const int 1 expr", K(ret)); + } else if (OB_FALSE_IT(select_item.expr_ = c_expr)) { + } else if (OB_FAIL(select_stmt->add_select_item(select_item))) { + LOG_WARN("failed to add select item", K(ret)); + } + } else if (OB_FAIL(session_info_->get_name_case_mode(case_mode))) { LOG_WARN("fail to get name case mode", K(ret)); } else if (OB_FAIL(ObResolverUtils::resolve_column_ref(node, case_mode, column_ref))) { LOG_WARN("fail to resolve table name", K(ret)); @@ -5785,6 +5808,7 @@ int ObSelectResolver::resolve_subquery_info(const ObIArray &subq subquery_resolver.set_is_sub_stmt(true); subquery_resolver.set_parent_namespace_resolver(this); subquery_resolver.set_current_view_level(current_view_level_); + subquery_resolver.set_in_exists_subquery(info.parents_expr_info_.has_member(IS_EXISTS)); set_query_ref_exec_params(info.ref_expr_ == NULL ? NULL : &info.ref_expr_->get_exec_params()); resolve_alias_for_subquery_ = !(T_FIELD_LIST_SCOPE == current_scope_ && info.parents_expr_info_.has_member(IS_AGG)); diff --git a/src/sql/resolver/dml/ob_view_table_resolver.cpp b/src/sql/resolver/dml/ob_view_table_resolver.cpp index 4f4e37e4a8..e3de18be17 100644 --- a/src/sql/resolver/dml/ob_view_table_resolver.cpp +++ b/src/sql/resolver/dml/ob_view_table_resolver.cpp @@ -257,6 +257,7 @@ int ObViewTableResolver::resolve_subquery_info(const ObIArray &s subquery_resolver.set_parent_namespace_resolver(this); subquery_resolver.set_parent_view_resolver(parent_view_resolver_); subquery_resolver.set_current_view_item(current_view_item); + subquery_resolver.set_in_exists_subquery(info.parents_expr_info_.has_member(IS_EXISTS)); set_query_ref_exec_params(info.ref_expr_ == NULL ? NULL : &info.ref_expr_->get_exec_params()); if (OB_FAIL(add_cte_table_to_children(subquery_resolver))) { LOG_WARN("add CTE table to children failed", K(ret)); diff --git a/src/sql/resolver/expr/ob_expr_info_flag.h b/src/sql/resolver/expr/ob_expr_info_flag.h index 84a5d97f55..b1ef79a98b 100644 --- a/src/sql/resolver/expr/ob_expr_info_flag.h +++ b/src/sql/resolver/expr/ob_expr_info_flag.h @@ -130,7 +130,8 @@ enum ObExprInfoFlag IS_ROWID, IS_ROWID_SIMPLE_COND, // rowid = const IS_ROWID_RANGE_COND, // rowid belongs to a range - IS_TABLE_ASSIGN // update t1 set c1 = const + IS_TABLE_ASSIGN, // update t1 set c1 = const + IS_EXISTS, }; #define IS_INFO_MASK_BEGIN IS_CONST @@ -241,6 +242,7 @@ inline const char* get_expr_info_flag_str(const ObExprInfoFlag flag) case IS_ROWID_SIMPLE_COND: { ret = "IS_ROWID_SIMPLE_COND"; break; } case IS_ROWID_RANGE_COND: { ret = "IS_ROWID_RANGE_COND"; break; } case IS_TABLE_ASSIGN: { ret = "IS_TABLE_ASSIGN"; break; } + case IS_EXISTS: { ret = "IS_EXISTS"; break; } default: break; } diff --git a/src/sql/resolver/expr/ob_raw_expr_info_extractor.cpp b/src/sql/resolver/expr/ob_raw_expr_info_extractor.cpp index f3643454e4..2dee8b78eb 100644 --- a/src/sql/resolver/expr/ob_raw_expr_info_extractor.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_info_extractor.cpp @@ -234,6 +234,12 @@ int ObRawExprInfoExtractor::visit(ObOpRawExpr &expr) LOG_WARN("failed to add flag IS_CONNECT_BY_ROOT", K(ret)); } break; + case T_OP_EXISTS: + case T_OP_NOT_EXISTS: + if (OB_FAIL(expr.add_flag(IS_EXISTS))) { + LOG_WARN("failed to add flag IS_EXISTS", K(ret)); + } + break; default: break; } diff --git a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp index aa27f57d1d..6cb3673906 100644 --- a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp @@ -577,7 +577,12 @@ int ObRawExprResolverImpl::do_recursive_resolve(const ParseNode *node, break; } case T_OP_EXISTS: - //fall through + if (OB_FAIL(ctx_.parents_expr_info_.add_member(IS_EXISTS))) { + LOG_WARN("failed to add member", K(ret)); + } else if (OB_FAIL(process_any_or_all_node(node, expr))) { + LOG_WARN("fail to process exists node", K(ret), K(node)); + } + break; case T_ANY: //fall through case T_ALL: {