From 1777c9769eafa406163a298fef2bfdc95d4ce357 Mon Sep 17 00:00:00 2001 From: obdev Date: Mon, 19 Jul 2021 21:27:14 +0800 Subject: [PATCH] cherry-pick from 3_1_x_release to 3.1_opensource_release --- .../mysqlclient/ob_server_connection_pool.cpp | 7 +- src/share/ob_errno.cpp | 4 +- src/share/ob_errno.def | 2 +- src/share/ob_errno.h | 2 +- src/share/ob_index_builder_util.cpp | 9 +- src/share/schema/ob_schema_utils.cpp | 63 ++++------ .../expr/ob_expr_sys_connect_by_path.cpp | 35 ++++-- src/sql/resolver/ddl/ob_ddl_resolver.cpp | 32 +++-- src/sql/resolver/expr/ob_raw_expr.cpp | 31 +++++ src/sql/resolver/expr/ob_raw_expr.h | 2 + src/sql/resolver/expr/ob_raw_expr_util.cpp | 81 +++++++++++-- src/sql/resolver/expr/ob_raw_expr_util.h | 16 ++- src/sql/resolver/ob_resolver_utils.cpp | 114 +++++++++++++++++- src/sql/resolver/ob_resolver_utils.h | 15 ++- 14 files changed, 315 insertions(+), 98 deletions(-) diff --git a/deps/oblib/src/lib/mysqlclient/ob_server_connection_pool.cpp b/deps/oblib/src/lib/mysqlclient/ob_server_connection_pool.cpp index 2a57d10e11..14b046f076 100644 --- a/deps/oblib/src/lib/mysqlclient/ob_server_connection_pool.cpp +++ b/deps/oblib/src/lib/mysqlclient/ob_server_connection_pool.cpp @@ -183,12 +183,13 @@ int ObServerConnectionPool::init_dblink(uint64_t dblink_id, const ObAddr& server LOG_WARN("db param buffer is not enough", K(ret), K(dblink_id), K(db_tenant), K(db_user), K(db_pass), K(db_name)); } else { dblink_id_ = dblink_id; - (void)snprintf(db_user_, sizeof(db_user_), "%s@%s", db_user.ptr(), db_tenant.ptr()); - (void)snprintf(db_pass_, sizeof(db_pass_), "%s", db_pass.ptr()); + (void)snprintf( + db_user_, sizeof(db_user_), "%.*s@%.*s", db_user.length(), db_user.ptr(), db_tenant.length(), db_tenant.ptr()); + (void)snprintf(db_pass_, sizeof(db_pass_), "%.*s", db_pass.length(), db_pass.ptr()); // https://baike.baidu.com/item/mysql_real_connect/4007597 // if db is NULL, the default database is used. if (!db_name.empty()) { - (void)snprintf(db_name_, sizeof(db_name_), "%s", db_name.ptr()); + (void)snprintf(db_name_, sizeof(db_name_), "%.*s", db_name.length(), db_name.ptr()); } } return ret; diff --git a/src/share/ob_errno.cpp b/src/share/ob_errno.cpp index c505e1761a..973a173f12 100644 --- a/src/share/ob_errno.cpp +++ b/src/share/ob_errno.cpp @@ -11214,9 +11214,9 @@ static struct ObStrErrorInit { MYSQL_ERRNO[-OB_ERR_ONLY_PURE_FUNC_CANBE_VIRTUAL_COLUMN_EXPRESSION] = -1; SQLSTATE[-OB_ERR_ONLY_PURE_FUNC_CANBE_VIRTUAL_COLUMN_EXPRESSION] = "HY000"; STR_ERROR[-OB_ERR_ONLY_PURE_FUNC_CANBE_VIRTUAL_COLUMN_EXPRESSION] = - "only pure functions can be specified in a virtual column expression"; + "Expression of generated column contains a disallowed function"; STR_USER_ERROR[-OB_ERR_ONLY_PURE_FUNC_CANBE_VIRTUAL_COLUMN_EXPRESSION] = - "only pure functions can be specified in a virtual column expression"; + "Expression of generated column contains a disallowed function"; ORACLE_ERRNO[-OB_ERR_ONLY_PURE_FUNC_CANBE_VIRTUAL_COLUMN_EXPRESSION] = 54002; ORACLE_STR_ERROR[-OB_ERR_ONLY_PURE_FUNC_CANBE_VIRTUAL_COLUMN_EXPRESSION] = "ORA-54002: only pure functions can be specified in a virtual column expression"; diff --git a/src/share/ob_errno.def b/src/share/ob_errno.def index 4299480c37..670dc5432b 100644 --- a/src/share/ob_errno.def +++ b/src/share/ob_errno.def @@ -1284,7 +1284,7 @@ DEFINE_ORACLE_ERROR(OB_ROWID_VIEW_NO_KEY_PRESERVED, -5902, -1, "HY000", "cannot DEFINE_ORACLE_ERROR(OB_ROWID_VIEW_HAS_DISTINCT_ETC, -5903, -1, "HY000", "cannot select ROWID from, or sample, a view with DISTINCT, GROUP BY, etc", 1446, "cannot select ROWID from, or sample, a view with DISTINCT, GROUP BY, etc"); DEFINE_ORACLE_ERROR(OB_ERR_AT_LEAST_ONE_COLUMN_NOT_VIRTUAL, -5904, -1, "HY000", "table must have at least 1 column that is not virtual", 54037, "table must have at least 1 column that is not virtual"); DEFINE_ORACLE_ERROR(OB_ERR_ONLY_PURE_FUNC_CANBE_INDEXED, -5905, -1, "HY000", "only pure functions can be indexed", 1743, "only pure functions can be indexed"); -DEFINE_ORACLE_ERROR(OB_ERR_ONLY_PURE_FUNC_CANBE_VIRTUAL_COLUMN_EXPRESSION, -5906, -1, "HY000", "only pure functions can be specified in a virtual column expression", 54002, "only pure functions can be specified in a virtual column expression"); +DEFINE_ORACLE_ERROR(OB_ERR_ONLY_PURE_FUNC_CANBE_VIRTUAL_COLUMN_EXPRESSION, -5906, -1, "HY000", "Expression of generated column contains a disallowed function", 54002, "only pure functions can be specified in a virtual column expression"); DEFINE_ORACLE_ERROR(OB_ERR_UPDATE_OPERATION_ON_VIRTUAL_COLUMNS, -5907, -1, "HY000", "UPDATE operation disallowed on virtual columns", 54017, "UPDATE operation disallowed on virtual columns"); DEFINE_ORACLE_ERROR(OB_ERR_INVALID_COLUMN_EXPRESSION, -5908, -1, "HY000", "Invalid column expression was specified", 54016, "Invalid column expression was specified"); DEFINE_ORACLE_ERROR(OB_ERR_IDENTITY_COLUMN_COUNT_EXCE_LIMIT, -5909, -1, "HY000", "table can have only one identity column", 30669, "table can have only one identity column"); diff --git a/src/share/ob_errno.h b/src/share/ob_errno.h index 35c3967f28..8e4ba57d78 100644 --- a/src/share/ob_errno.h +++ b/src/share/ob_errno.h @@ -2549,7 +2549,7 @@ constexpr int OB_ERR_INVALID_DATE_MSG_FMT_V2 = -4219; #define OB_ERR_AT_LEAST_ONE_COLUMN_NOT_VIRTUAL__USER_ERROR_MSG "table must have at least 1 column that is not virtual" #define OB_ERR_ONLY_PURE_FUNC_CANBE_INDEXED__USER_ERROR_MSG "only pure functions can be indexed" #define OB_ERR_ONLY_PURE_FUNC_CANBE_VIRTUAL_COLUMN_EXPRESSION__USER_ERROR_MSG \ - "only pure functions can be specified in a virtual column expression" + "Expression of generated column contains a disallowed function" #define OB_ERR_UPDATE_OPERATION_ON_VIRTUAL_COLUMNS__USER_ERROR_MSG "UPDATE operation disallowed on virtual columns" #define OB_ERR_INVALID_COLUMN_EXPRESSION__USER_ERROR_MSG "Invalid column expression was specified" #define OB_ERR_IDENTITY_COLUMN_COUNT_EXCE_LIMIT__USER_ERROR_MSG "table can have only one identity column" diff --git a/src/share/ob_index_builder_util.cpp b/src/share/ob_index_builder_util.cpp index 028c528b73..4ba6e77058 100644 --- a/src/share/ob_index_builder_util.cpp +++ b/src/share/ob_index_builder_util.cpp @@ -552,8 +552,13 @@ int ObIndexBuilderUtil::adjust_ordinary_index_column_args( LOG_WARN("init session failed", K(ret)); } else if (OB_FAIL(session.load_default_sys_variable(false, false))) { LOG_WARN("session load default system variable failed", K(ret)); - } else if (OB_FAIL(ObRawExprUtils::build_generated_column_expr( - index_expr_def, expr_factory, session, data_schema, expr))) { + } else if (OB_FAIL(ObRawExprUtils::build_generated_column_expr(index_expr_def, + expr_factory, + session, + data_schema, + expr, + NULL, + ObResolverUtils::CHECK_FOR_FUNCTION_INDEX))) { LOG_WARN("build generated column expr failed", K(ret)); } else if (!expr->is_deterministic()) { ret = OB_ERR_ONLY_PURE_FUNC_CANBE_INDEXED; diff --git a/src/share/schema/ob_schema_utils.cpp b/src/share/schema/ob_schema_utils.cpp index 7cf6bed46b..339da53e63 100644 --- a/src/share/schema/ob_schema_utils.cpp +++ b/src/share/schema/ob_schema_utils.cpp @@ -22,7 +22,7 @@ #include "share/schema/ob_server_schema_service.h" #include "share/ob_cluster_type.h" #include "share/ob_get_compat_mode.h" -#include "sql/resolver/expr/ob_raw_expr_util.h" +#include "sql/resolver/ob_resolver_utils.h" #include "sql/session/ob_sql_session_info.h" #include "observer/ob_server_struct.h" namespace oceanbase { @@ -145,51 +145,40 @@ int ObSchemaUtils::cascaded_generated_column(ObTableSchema& table_schema, ObColu int ret = OB_SUCCESS; ObString col_def; ObArenaAllocator allocator(ObModIds::OB_SCHEMA); - ObRawExprFactory expr_factory(allocator); - ObRawExpr* expr = NULL; - ObArray columns; + ObItemType root_expr_type = T_INVALID; + ObArray column_names; ObColumnSchemaV2* col_schema = NULL; bool is_oracle_mode = false; if (column.is_generated_column()) { - // This is the mock session, so test_init should be used, otherwise it cannot be initialized for tz_mgr - ObSQLSessionInfo default_session; - if (OB_FAIL(default_session.test_init(0, 0, 0, &allocator))) { - LOG_WARN("init empty session failed", K(ret)); - } else if (OB_FAIL(default_session.load_default_sys_variable(false, false))) { - LOG_WARN("session load default system variable failed", K(ret)); + if (ObSchemaService::g_liboblog_mode_ && GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_1471) { + // when 2.0liboblog fetch <1471 cluster, Parsing the column schema only needs to read orig_default_value + // Can not judge cur_default_value.is_null(), because the dependent column may have a default value + // cur_default_value is is_not_null, misjudgment + if (OB_FAIL(column.get_orig_default_value().get_string(col_def))) { + LOG_WARN("get orig default value failed", K(ret)); + } } else { - if (ObSchemaService::g_liboblog_mode_ && GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_1471) { - // when 2.0liboblog fetch <1471 cluster, Parsing the column schema only needs to read orig_default_value - // Can not judge cur_default_value.is_null(), because the dependent column may have a default value - // cur_default_value is is_not_null, misjudgment + // If the dependent column of the generated column has a change column, the current default value + // should be used instead of orig vaule + if (column.get_cur_default_value().is_null()) { if (OB_FAIL(column.get_orig_default_value().get_string(col_def))) { LOG_WARN("get orig default value failed", K(ret)); } } else { - // If the dependent column of the generated column has a change column, the current default value - // should be used instead of orig vaule - if (column.get_cur_default_value().is_null()) { - if (OB_FAIL(column.get_orig_default_value().get_string(col_def))) { - LOG_WARN("get orig default value failed", K(ret)); - } - } else { - if (OB_FAIL(column.get_cur_default_value().get_string(col_def))) { - LOG_WARN("get cur default value failed", K(ret)); - } + if (OB_FAIL(column.get_cur_default_value().get_string(col_def))) { + LOG_WARN("get cur default value failed", K(ret)); } } } if (OB_SUCC(ret)) { - if (OB_FAIL(ObRawExprUtils::build_generated_column_expr(col_def, expr_factory, default_session, expr, columns))) { + if (OB_FAIL(ObResolverUtils::resolve_generated_column_info(col_def, allocator, root_expr_type, column_names))) { LOG_WARN("get generated column expr failed", K(ret)); - } else if (OB_ISNULL(expr)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("expr is null"); - } else if (T_FUN_SYS_WORD_SEGMENT == expr->get_expr_type()) { + } else if (T_FUN_SYS_WORD_SEGMENT == root_expr_type) { column.add_column_flag(GENERATED_CTXCAT_CASCADE_FLAG); } else { - LOG_DEBUG("succ to build_generated_column_expr", K(col_def), KPC(expr), K(columns), K(table_schema)); + LOG_DEBUG( + "succ to resolve_generated_column_info", K(col_def), K(root_expr_type), K(column_names), K(table_schema)); } } @@ -202,18 +191,10 @@ int ObSchemaUtils::cascaded_generated_column(ObTableSchema& table_schema, ObColu // TODO: materialized view if (table_schema.is_table() || table_schema.is_tmp_table()) { - for (int64_t i = 0; OB_SUCC(ret) && i < columns.count(); ++i) { - // alter table t add b char(10) as(concat(a, '1')); oracle mode - // The pl implementation causes concat to be parsed into T_OBJ_ACCESS_REF, so column_name may be empty - if (is_oracle_mode && columns.at(i).access_idents_.count() > 0 && - columns.at(i).access_idents_[0].type_ != UNKNOWN) { - continue; - } else if (!columns.at(i).database_name_.empty() || !columns.at(i).tbl_name_.empty()) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("column is invalid", K(columns.at(i))); - } else if (OB_ISNULL(col_schema = table_schema.get_column_schema(columns.at(i).col_name_))) { + for (int64_t i = 0; OB_SUCC(ret) && i < column_names.count(); ++i) { + if (OB_ISNULL(col_schema = table_schema.get_column_schema(column_names.at(i)))) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("get column schema failed", K(columns.at(i))); + LOG_WARN("get column schema failed", K(column_names.at(i))); } else if (OB_FAIL(column.add_cascaded_column_id(col_schema->get_column_id()))) { LOG_WARN("add cascaded column id failed", K(ret)); } else { diff --git a/src/sql/engine/expr/ob_expr_sys_connect_by_path.cpp b/src/sql/engine/expr/ob_expr_sys_connect_by_path.cpp index 9fbeeeecc8..b0ae961088 100644 --- a/src/sql/engine/expr/ob_expr_sys_connect_by_path.cpp +++ b/src/sql/engine/expr/ob_expr_sys_connect_by_path.cpp @@ -28,18 +28,27 @@ int ObExprSysConnectByPath::calc_result_type2( ObExprResType& type, ObExprResType& type1, ObExprResType& type2, common::ObExprTypeCtx& type_ctx) const { int ret = OB_SUCCESS; - type.set_varchar(); - // The length value result is related to the row count and cannot be determined in the analysis stage - type.set_length(OB_MAX_VARCHAR_LENGTH); - ObExprResType types[2]; - type1.set_calc_type(ObVarcharType); - type2.set_calc_type(ObVarcharType); - types[0] = type1; - types[1] = type2; - if (OB_FAIL(aggregate_charsets_for_string_result(type, types, 2, type_ctx.get_coll_type()))) { - LOG_WARN("fail to aggregate charset", K(type1), K(type2), K(ret)); - } else if (OB_FAIL(aggregate_charsets_for_comparison(type, types, 2, type_ctx.get_coll_type()))) { - LOG_WARN("fail to aggregate charset", K(type1), K(type2), K(ret)); + if (is_oracle_mode()) { + ObSEArray params; + OZ(params.push_back(&type1)); + OZ(params.push_back(&type2)); + OZ(aggregate_string_type_and_charset_oracle(*type_ctx.get_session(), params, type, true)); + OZ(deduce_string_param_calc_type_and_charset(*type_ctx.get_session(), type, params)); + type.set_calc_meta(type); // old engine need to set the calc_meta of type + } else { + type.set_varchar(); + // The length value result is related to the row count and cannot be determined in the analysis stage + type.set_length(OB_MAX_VARCHAR_LENGTH); + ObExprResType types[2]; + type1.set_calc_type(ObVarcharType); + type2.set_calc_type(ObVarcharType); + types[0] = type1; + types[1] = type2; + if (OB_FAIL(aggregate_charsets_for_string_result(type, types, 2, type_ctx.get_coll_type()))) { + LOG_WARN("fail to aggregate charset", K(type1), K(type2), K(ret)); + } else if (OB_FAIL(aggregate_charsets_for_comparison(type, types, 2, type_ctx.get_coll_type()))) { + LOG_WARN("fail to aggregate charset", K(type1), K(type2), K(ret)); + } } return ret; } @@ -52,7 +61,7 @@ int ObExprSysConnectByPath::calc_result2( if (OB_ISNULL(expr_ctx.exec_ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("exec ctx is null", K(ret)); - } else if ((left.get_type() != ObVarcharType && left.get_type() != ObNullType) || right.get_type() != ObVarcharType) { + } else if ((!left.is_string_type() && left.get_type() != ObNullType) || !right.is_string_type()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid input type", K(left), K(right), K(ret)); } else { diff --git a/src/sql/resolver/ddl/ob_ddl_resolver.cpp b/src/sql/resolver/ddl/ob_ddl_resolver.cpp index 4bf3f84238..a3adebf68c 100644 --- a/src/sql/resolver/ddl/ob_ddl_resolver.cpp +++ b/src/sql/resolver/ddl/ob_ddl_resolver.cpp @@ -513,13 +513,13 @@ int ObDDLResolver::set_database_name(const ObString& database_name) return ret; } -int ObDDLResolver::resolve_table_id_pre(ParseNode *node) +int ObDDLResolver::resolve_table_id_pre(ParseNode* node) { int ret = OB_SUCCESS; if (NULL != node) { - ParseNode *option_node = NULL; + ParseNode* option_node = NULL; int32_t num = 0; - if(T_TABLE_OPTION_LIST != node->type_ || node->num_child_ < 1) { + if (T_TABLE_OPTION_LIST != node->type_ || node->num_child_ < 1) { ret = OB_ERR_UNEXPECTED; SQL_RESV_LOG(WARN, "invalid parse node", K(ret)); } else if (OB_ISNULL(node->children_) || OB_ISNULL(session_info_)) { @@ -2945,12 +2945,8 @@ int ObDDLResolver::check_urowid_column_length(const share::schema::ObColumnSchem return ret; } -int ObDDLResolver::check_text_length(ObCharsetType cs_type, - ObCollationType co_type, - const char* name, - ObObjType& type, - int32_t& length, - bool need_rewrite_length) +int ObDDLResolver::check_text_length(ObCharsetType cs_type, ObCollationType co_type, const char* name, ObObjType& type, + int32_t& length, bool need_rewrite_length) { int ret = OB_SUCCESS; int64_t mbmaxlen = 0; @@ -3009,14 +3005,13 @@ int ObDDLResolver::check_text_length(ObCharsetType cs_type, // old version ObTinyTextType, ObTextType, ObMediumTextType, ObLongTextType max_length is incorrect // correct max_legth is ObTinyTextType:255 etc. // so when create new user table, must rewrite max column length -int ObDDLResolver::rewrite_text_length_mysql(ObObjType &type, int32_t &length) +int ObDDLResolver::rewrite_text_length_mysql(ObObjType& type, int32_t& length) { int ret = OB_SUCCESS; int32_t max_length = ObAccuracy::MAX_ACCURACY[type].get_length(); if (length < 0 || length > max_length) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("length can not be less than 0 or larger than max_length", - K(ret), K(type), K(length), K(max_length)); + LOG_WARN("length can not be less than 0 or larger than max_length", K(ret), K(type), K(length), K(max_length)); } else if (ob_is_text_tc(type) && max_length == length) { length = length - 1; } @@ -3036,11 +3031,11 @@ int ObDDLResolver::check_text_column_length_and_promote(ObColumnSchemaV2& column need_check_length = false; } if (OB_FAIL(check_text_length(column.get_charset_type(), - column.get_collation_type(), - column.get_column_name(), - type, - length, - need_check_length))) { + column.get_collation_type(), + column.get_column_name(), + type, + length, + need_check_length))) { LOG_WARN("failed to check text length", K(ret), K(column)); } else { column.set_data_type(type); @@ -3772,7 +3767,8 @@ int ObDDLResolver::check_default_value(ObObj& default_value, const common::ObTim LOG_WARN("session load default system variable failed", K(ret)); } else if (OB_FAIL(input_default_value.get_string(expr_str))) { LOG_WARN("get expr string from default value failed", K(ret), K(input_default_value)); - } else if (OB_FAIL(ObResolverUtils::resolve_generated_column_expr(params, expr_str, table_schema, column, expr))) { + } else if (OB_FAIL(ObResolverUtils::resolve_generated_column_expr( + params, expr_str, table_schema, column, expr, ObResolverUtils::CHECK_FOR_GENERATED_COLUMN))) { LOG_WARN("resolve generated column expr failed", K(ret)); } else if (column.get_meta_type().is_null()) { column.set_data_type(expr->get_data_type()); diff --git a/src/sql/resolver/expr/ob_raw_expr.cpp b/src/sql/resolver/expr/ob_raw_expr.cpp index de5e6d9d00..fec70782db 100644 --- a/src/sql/resolver/expr/ob_raw_expr.cpp +++ b/src/sql/resolver/expr/ob_raw_expr.cpp @@ -472,6 +472,37 @@ int ObRawExpr::set_enum_set_values(const common::ObIArray& val return ret; } +bool ObRawExpr::is_non_pure_sys_func_expr() const +{ + if (lib::is_oracle_mode()) { + if (T_FUN_SYS_LOCALTIMESTAMP == type_ || T_FUN_SYS_SESSIONTIMEZONE == type_ || T_FUN_SYS_DBTIMEZONE == type_ || + T_FUN_SYS_SYSDATE == type_ || T_FUN_SYS_SYSTIMESTAMP == type_ || T_FUN_SYS_UID == type_ || + T_FUN_SYS_USER == type_ || T_FUN_SYS_CUR_TIMESTAMP == type_ || T_FUN_SYS_GUID == type_ || + T_FUN_SYS_CUR_DATE == type_ || T_FUN_SYS_USERENV == type_ || T_FUN_SYS_REGEXP_REPLACE == type_) { + return true; + } + } else { + if (T_FUN_SYS_CONNECTION_ID == type_ || T_FUN_SYS_VERSION == type_ || T_FUN_SYS_CURRENT_USER == type_ || + T_FUN_SYS_USER == type_ || T_FUN_SYS_DATABASE == type_ || T_FUN_SYS_SYSDATE == type_ || + T_FUN_SYS_CUR_DATE == type_ || T_FUN_SYS_CUR_TIME == type_ || T_FUN_SYS_CUR_TIMESTAMP == type_ || + T_FUN_SYS_UNIX_TIMESTAMP == type_ || T_FUN_SYS_UTC_TIMESTAMP == type_ || T_FUN_SYS_RAND == type_ || + T_FUN_SYS_UUID == type_ || T_FUN_SYS_SLEEP == type_ || T_FUN_SYS_LAST_INSERT_ID == type_ || + T_FUN_SYS_ROW_COUNT == type_ || T_FUN_SYS_FOUND_ROWS == type_ || T_FUN_SYS_REGEXP_INSTR == type_ || + T_FUN_SYS_REGEXP_LIKE == type_ || T_FUN_SYS_REGEXP_REPLACE == type_ || T_FUN_SYS_REGEXP_SUBSTR == type_) { + return true; + } + } + return false; +} + +bool ObRawExpr::is_specified_pseudocolumn_expr() const +{ + if (T_FUN_SYS_ROWNUM == type_ || T_LEVEL == type_ || T_CONNECT_BY_ISCYCLE == type_ || T_CONNECT_BY_ISLEAF == type_) { + return true; + } + return false; +} + //////////////////////////////////////////////////////////////// int ObConstRawExpr::assign(const ObConstRawExpr& other) { diff --git a/src/sql/resolver/expr/ob_raw_expr.h b/src/sql/resolver/expr/ob_raw_expr.h index b6f915652d..46590622d8 100644 --- a/src/sql/resolver/expr/ob_raw_expr.h +++ b/src/sql/resolver/expr/ob_raw_expr.h @@ -1351,6 +1351,8 @@ public: { return T_FUN_PL_ASSOCIATIVE_INDEX == get_expr_type(); } + bool is_non_pure_sys_func_expr() const; + bool is_specified_pseudocolumn_expr() const; void set_alias_column_name(const common::ObString& alias_name) { alias_column_name_ = alias_name; diff --git a/src/sql/resolver/expr/ob_raw_expr_util.cpp b/src/sql/resolver/expr/ob_raw_expr_util.cpp index 815d40060b..e1e4d3c1f7 100644 --- a/src/sql/resolver/expr/ob_raw_expr_util.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_util.cpp @@ -1014,7 +1014,7 @@ int ObRawExprUtils::parse_bool_expr_node_from_str( int ObRawExprUtils::build_generated_column_expr(const ObString& expr_str, ObRawExprFactory& expr_factory, const ObSQLSessionInfo& session_info, ObRawExpr*& expr, ObIArray& columns, - const ObSchemaChecker* schema_checker) + const ObSchemaChecker* schema_checker, const ObResolverUtils::PureFunctionCheckStatus check_status) { int ret = OB_SUCCESS; const ParseNode* node = NULL; @@ -1023,15 +1023,73 @@ int ObRawExprUtils::build_generated_column_expr(const ObString& expr_str, ObRawE } else if (OB_ISNULL(node)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("node is null"); - } else if (OB_FAIL(build_generated_column_expr(expr_factory, session_info, *node, expr, columns, schema_checker))) { + } else if (OB_FAIL(build_generated_column_expr( + expr_factory, session_info, *node, expr, columns, schema_checker, check_status))) { LOG_WARN("build generated column expr failed", K(ret)); } return ret; } +int ObRawExprUtils::check_deterministic( + const ObRawExpr* expr, ObIAllocator& allocator, const ObResolverUtils::PureFunctionCheckStatus check_status) +{ + int ret = OB_SUCCESS; + CK(OB_NOT_NULL(expr)); + CK(expr->get_children_count() >= 0); + ObList expr_queue(allocator); + OZ(expr_queue.push_back(expr)); + const ObRawExpr* cur_expr = NULL; + while (OB_SUCC(ret) && expr_queue.size() > 0) { + OZ(expr_queue.pop_front(cur_expr)); + CK(OB_NOT_NULL(cur_expr)); + OZ(check_deterministic_single(cur_expr, check_status)); + for (int i = 0; OB_SUCC(ret) && i < cur_expr->get_param_count(); ++i) { + OZ(expr_queue.push_back(cur_expr->get_param_expr(i))); + } + } + return ret; +} + +int ObRawExprUtils::check_deterministic_single( + const ObRawExpr* expr, const ObResolverUtils::PureFunctionCheckStatus check_status) +{ + int ret = OB_SUCCESS; + CK(OB_NOT_NULL(expr)); + if (OB_SUCC(ret) && ObResolverUtils::DISABLE_CHECK != check_status) { + if (expr->is_sys_func_expr()) { + if (expr->is_non_pure_sys_func_expr()) { + if (ObResolverUtils::CHECK_FOR_GENERATED_COLUMN == check_status) { + ret = OB_ERR_ONLY_PURE_FUNC_CANBE_VIRTUAL_COLUMN_EXPRESSION; + } else if (ObResolverUtils::CHECK_FOR_FUNCTION_INDEX == check_status) { + ret = OB_ERR_ONLY_PURE_FUNC_CANBE_INDEXED; + } + LOG_WARN("only pure sys function can be indexed", K(ret), K(check_status), K(*expr)); + } else if (T_FUN_SYS_ROWNUM == expr->get_expr_type()) { + ret = OB_ERR_CBY_PSEUDO_COLUMN_NOT_ALLOWED; + LOG_WARN("ROWNUM is not allowed", K(ret), K(*expr)); + } + } else if (expr->is_pseudo_column_expr()) { + if (expr->is_specified_pseudocolumn_expr()) { + ret = OB_ERR_CBY_PSEUDO_COLUMN_NOT_ALLOWED; + LOG_WARN("not allowed pesudo column", K(ret), K(*expr)); + } + } else if (expr->is_udf_expr()) { + if (lib::is_mysql_mode()) { + ret = OB_ERR_ONLY_PURE_FUNC_CANBE_VIRTUAL_COLUMN_EXPRESSION; + LOG_WARN("user-defined functions are not allowd in generated column", K(ret), K(*expr)); + } else { + ret = OB_NOT_SUPPORTED; + LOG_WARN("user-defined function is not supported", K(ret), K(*expr)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "The user-defined function"); + } + } + } + return ret; +} + int ObRawExprUtils::build_generated_column_expr(const ObString& expr_str, ObRawExprFactory& expr_factory, const ObSQLSessionInfo& session_info, const ObTableSchema& table_schema, ObRawExpr*& expr, - const ObSchemaChecker* schema_checker) + const ObSchemaChecker* schema_checker, const ObResolverUtils::PureFunctionCheckStatus check_status) { int ret = OB_SUCCESS; const ParseNode* node = NULL; @@ -1042,9 +1100,11 @@ int ObRawExprUtils::build_generated_column_expr(const ObString& expr_str, ObRawE } else if (OB_ISNULL(node)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("node is null"); - } else if (OB_FAIL(build_generated_column_expr(expr_factory, session_info, *node, expr, columns, schema_checker))) { + } else if (OB_FAIL(build_generated_column_expr( + expr_factory, session_info, *node, expr, columns, schema_checker, check_status))) { LOG_WARN("build generated column expr failed", K(ret), K(expr_str)); } + for (int64_t i = 0; OB_SUCC(ret) && i < columns.count(); i++) { const ObQualifiedName& q_name = columns.at(i); if (OB_UNLIKELY(!q_name.database_name_.empty())) { @@ -1121,7 +1181,8 @@ int ObRawExprUtils::build_check_constraint_expr(ObRawExprFactory& expr_factory, } int ObRawExprUtils::build_generated_column_expr(ObRawExprFactory& expr_factory, const ObSQLSessionInfo& session_info, - const ParseNode& node, ObRawExpr*& expr, ObIArray& columns, const ObSchemaChecker* schema_checker) + const ParseNode& node, ObRawExpr*& expr, ObIArray& columns, const ObSchemaChecker* schema_checker, + const ObResolverUtils::PureFunctionCheckStatus check_status) { int ret = OB_SUCCESS; ObArray sys_vars; @@ -1188,6 +1249,10 @@ int ObRawExprUtils::build_generated_column_expr(ObRawExprFactory& expr_factory, OZ(columns.assign(real_columns), real_columns); } } + // check whether the expression is deterministic recursively + if (OB_SUCC(ret) && ObResolverUtils::DISABLE_CHECK != check_status) { + OZ(check_deterministic(expr, expr_factory.get_allocator(), check_status)); + } return ret; } @@ -1259,12 +1324,14 @@ int ObRawExprUtils::build_raw_expr(ObRawExprFactory& expr_factory, const ObSQLSe int ObRawExprUtils::build_generated_column_expr(const ObString& expr_str, ObRawExprFactory& expr_factory, const ObSQLSessionInfo& session_info, uint64_t table_id, const ObTableSchema& table_schema, - const ObColumnSchemaV2& gen_col_schema, ObRawExpr*& expr, const ObSchemaChecker* schema_checker) + const ObColumnSchemaV2& gen_col_schema, ObRawExpr*& expr, const ObSchemaChecker* schema_checker, + const ObResolverUtils::PureFunctionCheckStatus check_status) { int ret = OB_SUCCESS; ObArray columns; const ObColumnSchemaV2* col_schema = NULL; - if (OB_FAIL(build_generated_column_expr(expr_str, expr_factory, session_info, expr, columns, schema_checker))) { + if (OB_FAIL(build_generated_column_expr( + expr_str, expr_factory, session_info, expr, columns, schema_checker, check_status))) { LOG_WARN("build generated column expr failed", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < columns.count(); ++i) { diff --git a/src/sql/resolver/expr/ob_raw_expr_util.h b/src/sql/resolver/expr/ob_raw_expr_util.h index b9e021dc45..826ffb6a75 100644 --- a/src/sql/resolver/expr/ob_raw_expr_util.h +++ b/src/sql/resolver/expr/ob_raw_expr_util.h @@ -174,19 +174,27 @@ public: const common::ObString& expr_str, common::ObIAllocator& allocator, const ParseNode*& node); static int build_check_constraint_expr(ObRawExprFactory& expr_factory, const ObSQLSessionInfo& session_info, const ParseNode& node, ObRawExpr*& expr, common::ObIArray& columns); + static int check_deterministic(const ObRawExpr* expr, common::ObIAllocator& allocator, + const ObResolverUtils::PureFunctionCheckStatus check_status = ObResolverUtils::DISABLE_CHECK); + static int check_deterministic_single(const ObRawExpr* expr, + const ObResolverUtils::PureFunctionCheckStatus check_status = ObResolverUtils::DISABLE_CHECK); static int build_generated_column_expr(ObRawExprFactory& expr_factory, const ObSQLSessionInfo& session_info, const ParseNode& node, ObRawExpr*& expr, common::ObIArray& columns, - const ObSchemaChecker* schema_checker = NULL); + const ObSchemaChecker* schema_checker = NULL, + const ObResolverUtils::PureFunctionCheckStatus check_status = ObResolverUtils::DISABLE_CHECK); static int build_generated_column_expr(const common::ObString& expr_str, ObRawExprFactory& expr_factory, const ObSQLSessionInfo& session_info, ObRawExpr*& expr, common::ObIArray& columns, - const ObSchemaChecker* schema_checker = NULL); + const ObSchemaChecker* schema_checker = NULL, + const ObResolverUtils::PureFunctionCheckStatus check_status = ObResolverUtils::DISABLE_CHECK); static int build_generated_column_expr(const common::ObString& expr_str, ObRawExprFactory& expr_factory, const ObSQLSessionInfo& session_info, const share::schema::ObTableSchema& table_schema, ObRawExpr*& expr, - const ObSchemaChecker* schema_checker = NULL); + const ObSchemaChecker* schema_checker = NULL, + const ObResolverUtils::PureFunctionCheckStatus check_status = ObResolverUtils::DISABLE_CHECK); static int build_generated_column_expr(const common::ObString& expr_str, ObRawExprFactory& expr_factory, const ObSQLSessionInfo& session_info, uint64_t table_id, const share::schema::ObTableSchema& table_schema, const share::schema::ObColumnSchemaV2& gen_col_schema, ObRawExpr*& expr, - const ObSchemaChecker* schema_checker = NULL); + const ObSchemaChecker* schema_checker = NULL, + const ObResolverUtils::PureFunctionCheckStatus check_status = ObResolverUtils::DISABLE_CHECK); static int build_raw_expr(ObRawExprFactory& expr_factory, const ObSQLSessionInfo& session_info, const ParseNode& node, ObRawExpr*& expr, common::ObIArray& columns, common::ObIArray& sys_vars, common::ObIArray& aggr_exprs, common::ObIArray& win_exprs, diff --git a/src/sql/resolver/ob_resolver_utils.cpp b/src/sql/resolver/ob_resolver_utils.cpp index 8052d00207..8aa4b11428 100644 --- a/src/sql/resolver/ob_resolver_utils.cpp +++ b/src/sql/resolver/ob_resolver_utils.cpp @@ -3078,7 +3078,8 @@ int ObResolverUtils::resolve_partition_expr(ObResolverParams& params, const Pars } int ObResolverUtils::resolve_generated_column_expr(ObResolverParams& params, const ObString& expr_str, - ObTableSchema& tbl_schema, ObColumnSchemaV2& generated_column, ObRawExpr*& expr) + ObTableSchema& tbl_schema, ObColumnSchemaV2& generated_column, ObRawExpr*& expr, + const PureFunctionCheckStatus check_status) { int ret = OB_SUCCESS; const ParseNode* expr_node = NULL; @@ -3087,14 +3088,16 @@ int ObResolverUtils::resolve_generated_column_expr(ObResolverParams& params, con LOG_WARN("allocator is null"); } else if (OB_FAIL(ObRawExprUtils::parse_expr_node_from_str(expr_str, *params.allocator_, expr_node))) { LOG_WARN("parse expr node from str failed", K(ret), K(expr_str)); - } else if (OB_FAIL(resolve_generated_column_expr(params, expr_node, tbl_schema, generated_column, expr))) { + } else if (OB_FAIL( + resolve_generated_column_expr(params, expr_node, tbl_schema, generated_column, expr, check_status))) { LOG_WARN("resolve generated column expr failed", K(ret), K(expr_str)); } return ret; } int ObResolverUtils::resolve_generated_column_expr(ObResolverParams& params, const ParseNode* node, - ObTableSchema& tbl_schema, ObColumnSchemaV2& generated_column, ObRawExpr*& expr) + ObTableSchema& tbl_schema, ObColumnSchemaV2& generated_column, ObRawExpr*& expr, + const PureFunctionCheckStatus check_status) { int ret = OB_SUCCESS; ObColumnSchemaV2* col_schema = NULL; @@ -3105,7 +3108,8 @@ int ObResolverUtils::resolve_generated_column_expr(ObResolverParams& params, con if (OB_ISNULL(expr_factory) || OB_ISNULL(session_info) || OB_ISNULL(node)) { ret = OB_NOT_INIT; LOG_WARN("resolve status is invalid", K_(params.expr_factory), K(session_info), K(node)); - } else if (OB_FAIL(ObRawExprUtils::build_generated_column_expr(*expr_factory, *session_info, *node, expr, columns))) { + } else if (OB_FAIL(ObRawExprUtils::build_generated_column_expr( + *expr_factory, *session_info, *node, expr, columns, params.schema_checker_, check_status))) { LOG_WARN("build generated column expr failed", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < columns.count(); ++i) { @@ -3134,6 +3138,10 @@ int ObResolverUtils::resolve_generated_column_expr(ObResolverParams& params, con ret = OB_NOT_SUPPORTED; LOG_WARN("Define a blob column in generated column def is not supported", K(ret)); LOG_USER_ERROR(OB_NOT_SUPPORTED, "blob column in generated column definition"); + } else if (share::is_mysql_mode() && col_schema->is_autoincrement()) { + ret = OB_NOT_SUPPORTED; + LOG_WARN("generated column cannot refer to auto-increment column", K(ret), K(*expr)); + LOG_USER_ERROR(OB_NOT_SUPPORTED, "generated column refer to auto-increment column"); } else if (OB_FAIL(ObRawExprUtils::init_column_expr(*col_schema, *q_name.ref_expr_))) { LOG_WARN("init column expr failed", K(ret)); } else if (OB_FAIL(generated_column.add_cascaded_column_id(col_schema->get_column_id()))) { @@ -3203,6 +3211,104 @@ int ObResolverUtils::resolve_generated_column_expr(ObResolverParams& params, con return ret; } +// This function is used to resolve the dependent columns of generated column when retrieve schema. +// We use this function instead of build_generated_column_expr because there is not a thread-safe +// mem_context and the expr is not necessary. +int ObResolverUtils::resolve_generated_column_info( + const ObString& expr_str, ObIAllocator& allocator, ObItemType& root_expr_type, ObIArray& column_names) +{ + int ret = OB_SUCCESS; + const ParseNode* node = NULL; + if (OB_FAIL(ObRawExprUtils::parse_expr_node_from_str(expr_str, allocator, node))) { + LOG_WARN("parse expr node from string failed", K(ret), K(expr_str)); + } else if (OB_ISNULL(node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("node is null", K(ret)); + } else if (OB_FAIL(SMART_CALL(resolve_column_info_recursively(node, column_names)))) { + LOG_WARN("failed to resolve column into"); + } else { + ObItemType type = node->type_; + if (T_FUN_SYS == type) { + if (OB_UNLIKELY(1 > node->num_child_) || OB_ISNULL(node->children_) || OB_ISNULL(node->children_[0])) { + ret = OB_ERR_PARSER_SYNTAX; + LOG_WARN("invalid node children for fun_sys node", K(ret)); + } else { + ObString func_name(node->children_[0]->str_len_, node->children_[0]->str_value_); + if (0 == func_name.case_compare("bin")) { + type = ObExprOperatorFactory::get_type_by_name("conv"); + } else if (0 == func_name.case_compare("oct")) { + type = ObExprOperatorFactory::get_type_by_name("conv"); + } else if (0 == func_name.case_compare("lcase")) { + type = ObExprOperatorFactory::get_type_by_name("lower"); + } else if (0 == func_name.case_compare("ucase")) { + type = ObExprOperatorFactory::get_type_by_name("upper"); + // don't alias "power" to "pow" in oracle mode + } else if (!lib::is_oracle_mode() && 0 == func_name.case_compare("power")) { + type = ObExprOperatorFactory::get_type_by_name("pow"); + } else if (0 == func_name.case_compare("ws")) { + type = ObExprOperatorFactory::get_type_by_name("word_segment"); + } else { + type = ObExprOperatorFactory::get_type_by_name(func_name); + } + if (OB_UNLIKELY(T_INVALID == (type))) { + ret = OB_ERR_FUNCTION_UNKNOWN; + LOG_WARN("function not exist", K(func_name), K(ret)); + } + } + } + OX(root_expr_type = type); + } + return ret; +} + +int ObResolverUtils::resolve_column_info_recursively(const ParseNode* node, ObIArray& column_names) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("node is null"); + } else if (T_COLUMN_REF == node->type_) { + if (OB_UNLIKELY(node->num_child_ != 3)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid node type", K_(node->type), K(node->num_child_), K(ret)); + } else if (OB_UNLIKELY(node->children_[0] != NULL || node->children_[1] != NULL)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("database node or table node is not null", K_(node->type), K(ret)); + } else if (OB_ISNULL(node->children_[2])) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("column node is null", K_(node->type), K(ret)); + } else if (OB_UNLIKELY(T_STAR == node->children_[2]->type_)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("column node can't be T_STAR", K_(node->type), K(ret)); + } else { + ObString column_name(static_cast(node->children_[2]->str_len_), node->children_[2]->str_value_); + if (OB_FAIL(column_names.push_back(column_name))) { + LOG_WARN("Add column failed", K(ret)); + } + } + } else if (T_OBJ_ACCESS_REF == node->type_) { + if (OB_UNLIKELY(node->num_child_ != 2)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid node type", K_(node->type), K(node->num_child_), K(ret)); + } else if (OB_ISNULL(node->children_[0])) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("node is NULL", K(node->num_child_)); + } else if (T_IDENT == node->children_[0]->type_) { + ObString column_name(static_cast(node->children_[0]->str_len_), node->children_[0]->str_value_); + OZ(column_names.push_back(column_name)); + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < node->num_child_; ++i) { + const ParseNode* child_node = node->children_[i]; + if (NULL == child_node) { + // do nothing + } else if (OB_FAIL(SMART_CALL(resolve_column_info_recursively(child_node, column_names)))) { + LOG_WARN("recursive resolve column node failed", K(ret)); + } + } + return ret; +} + int ObResolverUtils::resolve_default_expr_v2_column_expr( ObResolverParams& params, const ObString& expr_str, ObColumnSchemaV2& default_expr_v2_column, ObRawExpr*& expr) { diff --git a/src/sql/resolver/ob_resolver_utils.h b/src/sql/resolver/ob_resolver_utils.h index b90c8a447a..80f97aedfa 100644 --- a/src/sql/resolver/ob_resolver_utils.h +++ b/src/sql/resolver/ob_resolver_utils.h @@ -32,6 +32,7 @@ namespace oceanbase { namespace sql { +class ObRawExprUtils; class ObRoutineMatchInfo { public: struct MatchInfo { @@ -87,6 +88,11 @@ public: }; struct ObResolverUtils { enum RangeElementsNode { PARTITION_NAME_NODE = 0, PARTITION_ELEMENT_NODE = 1 }; + enum PureFunctionCheckStatus { + DISABLE_CHECK = 0, + CHECK_FOR_GENERATED_COLUMN, + CHECK_FOR_FUNCTION_INDEX, + }; static const int NAMENODE = 1; static ObItemType item_type_; @@ -184,9 +190,14 @@ public: const share::schema::ObTableSchema& tbl_schema, share::schema::ObPartitionFuncType part_func_type, ObRawExpr*& part_expr, common::ObIArray* part_keys); static int resolve_generated_column_expr(ObResolverParams& params, const common::ObString& expr_str, - share::schema::ObTableSchema& tbl_schema, share::schema::ObColumnSchemaV2& generated_column, ObRawExpr*& expr); + share::schema::ObTableSchema& tbl_schema, share::schema::ObColumnSchemaV2& generated_column, ObRawExpr*& expr, + const PureFunctionCheckStatus check_status = DISABLE_CHECK); static int resolve_generated_column_expr(ObResolverParams& params, const ParseNode* node, - share::schema::ObTableSchema& tbl_schema, share::schema::ObColumnSchemaV2& generated_column, ObRawExpr*& expr); + share::schema::ObTableSchema& tbl_schema, share::schema::ObColumnSchemaV2& generated_column, ObRawExpr*& expr, + const PureFunctionCheckStatus check_status = DISABLE_CHECK); + static int resolve_generated_column_info(const common::ObString& expr_str, ObIAllocator& allocator, + ObItemType& root_expr_type, common::ObIArray& column_names); + static int resolve_column_info_recursively(const ParseNode* node, common::ObIArray& column_names); static int resolve_default_expr_v2_column_expr(ObResolverParams& params, const common::ObString& expr_str, share::schema::ObColumnSchemaV2& default_expr_v2_column, ObRawExpr*& expr); static int resolve_default_expr_v2_column_expr(ObResolverParams& params, const ParseNode* node, -- GitLab