Files
oceanbase/src/sql/resolver/ob_resolver_utils.cpp
chuancy a474a9cf55 code: fix typo (#76)
* Update ob_dtl_rpc_channel.cpp

* Update ob_time_convert.cpp

* Update ob_time_convert.h

* Update ob_expr_date_add.cpp

* fix log spell error:faild -> failled, Faild -> Failed

* Update ob_optimizer_util.cpp

* Update ob_sql.cpp

* Update ob_optimizer_util.cpp

* Update ob_plan_cache_manager.cpp

* Update ob_partition_merge_task.cpp
2021-06-15 14:50:25 +08:00

5245 lines
212 KiB
C++

/**
* 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.
*/
#define USING_LOG_PREFIX SQL_RESV
#include "sql/resolver/ob_resolver_utils.h"
#include "lib/charset/ob_charset.h"
#include "lib/timezone/ob_time_convert.h"
#include "share/schema/ob_column_schema.h"
#include "share/object/ob_obj_cast.h"
#include "common/sql_mode/ob_sql_mode_utils.h"
#include "common/object/ob_obj_type.h"
#include "sql/parser/parse_malloc.h"
#include "sql/parser/parse_node.h"
#include "sql/parser/ob_parser.h"
#include "sql/resolver/ob_column_ref.h"
#include "sql/resolver/dml/ob_select_stmt.h"
#include "sql/resolver/expr/ob_raw_expr_resolver_impl.h"
#include "sql/resolver/expr/ob_raw_expr_util.h"
#include "sql/resolver/expr/ob_raw_expr_part_func_checker.h"
#include "sql/resolver/expr/ob_raw_expr_part_expr_checker.h"
#include "sql/resolver/expr/ob_raw_expr_printer.h"
#include "sql/resolver/ddl/ob_ddl_resolver.h"
#include "sql/ob_sql_utils.h"
#include "observer/ob_server_struct.h"
#include "sql/rewrite/ob_transform_utils.h"
#include "sql/engine/expr/ob_expr_column_conv.h"
namespace oceanbase {
using namespace common;
using namespace share::schema;
using namespace obrpc;
namespace sql {
ObItemType ObResolverUtils::item_type_ = T_INVALID;
const ObString ObResolverUtils::stmt_type_string[] = {
#define OB_STMT_TYPE_DEF(stmt_type, priv_check_func, id) ObString::make_string(#stmt_type),
#include "sql/resolver/ob_stmt_type.h"
#undef OB_STMT_TYPE_DEF
};
int ObResolverUtils::get_all_function_table_column_names(
const TableItem& table_item, ObResolverParams& params, ObIArray<ObString>& column_names)
{
UNUSED(table_item);
UNUSED(params);
UNUSED(column_names);
int ret = OB_NOT_SUPPORTED;
return ret;
}
int ObResolverUtils::check_function_table_column_exist(
const TableItem& table_item, ObResolverParams& params, const ObString& column_name)
{
UNUSED(table_item);
UNUSED(params);
UNUSED(column_name);
int ret = OB_NOT_SUPPORTED;
return ret;
}
int ObResolverUtils::resolve_extended_type_info(const ParseNode& str_list_node, ObIArray<ObString>& type_info_array)
{
int ret = OB_SUCCESS;
ObString cur_type_info;
CK(str_list_node.num_child_ > 0);
for (int64_t i = 0; OB_SUCC(ret) && i < str_list_node.num_child_; ++i) {
cur_type_info.reset();
const ParseNode* str_node = str_list_node.children_[i];
if (OB_ISNULL(str_node)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid str_node", K(ret), K(str_node), K(i));
} else if (FALSE_IT(cur_type_info.assign_ptr(
str_node->str_value_, static_cast<ObString::obstr_size_t>(str_node->str_len_)))) {
} else if (OB_FAIL(type_info_array.push_back(cur_type_info))) {
LOG_WARN("fail to push back type info", K(ret), K(i), K(cur_type_info));
}
}
return ret;
}
int ObResolverUtils::check_extended_type_info(common::ObIAllocator& alloc, ObIArray<ObString>& type_infos,
ObCollationType ori_cs_type, const ObString& col_name, ObObjType col_type, ObCollationType cs_type,
ObSQLMode sql_mode)
{
int ret = OB_SUCCESS;
ObString cur_type_info;
const ObString& sep = ObCharsetUtils::get_const_str(cs_type, ',');
int32_t dup_cnt;
// convert type infos from %ori_cs_type to %cs_type first
FOREACH_CNT_X(str, type_infos, OB_SUCC(ret))
{
OZ(ObCharset::charset_convert(alloc, *str, ori_cs_type, cs_type, *str));
}
if (OB_SUCC(ret)) {}
for (int64_t i = 0; OB_SUCC(ret) && i < type_infos.count(); ++i) {
ObString& cur_val = type_infos.at(i);
int32_t no_sp_len = static_cast<int32_t>(ObCharset::strlen_byte_no_sp(cs_type, cur_val.ptr(), cur_val.length()));
cur_val.assign_ptr(cur_val.ptr(), static_cast<ObString::obstr_size_t>(no_sp_len)); // remove tail space
int32_t char_len = static_cast<int32_t>(ObCharset::strlen_char(cs_type, cur_val.ptr(), cur_val.length()));
if (OB_UNLIKELY(char_len > OB_MAX_INTERVAL_VALUE_LENGTH)) { // max value length
ret = OB_ER_TOO_LONG_SET_ENUM_VALUE;
LOG_USER_ERROR(OB_ER_TOO_LONG_SET_ENUM_VALUE, col_name.length(), col_name.ptr());
} else if (ObSetType == col_type // set can't contain commas
&& 0 != ObCharset::instr(cs_type, cur_val.ptr(), cur_val.length(), sep.ptr(), sep.length())) {
ret = OB_ERR_ILLEGAL_VALUE_FOR_TYPE;
LOG_USER_ERROR(OB_ERR_ILLEGAL_VALUE_FOR_TYPE, "set", cur_val.length(), cur_val.ptr());
} else { /*do nothing*/
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(check_duplicates_in_type_infos( // check duplicate value
type_infos,
col_name,
col_type,
cs_type,
sql_mode,
dup_cnt))) {
LOG_WARN("fail to check duplicate", K(ret), K(dup_cnt), K(type_infos), K(col_name), K(col_type));
} else if (OB_FAIL(check_max_val_count( // check value count
col_type,
col_name,
type_infos.count(),
dup_cnt))) {
LOG_WARN("fail to check max val count", K(ret), K(col_type), K(col_name), K(type_infos), K(dup_cnt));
} else { /*do nothing*/
}
return ret;
}
int ObResolverUtils::check_duplicates_in_type_infos(const ObIArray<common::ObString>& type_infos,
const ObString& col_name, ObObjType col_type, ObCollationType cs_type, ObSQLMode sql_mode, int32_t& dup_cnt)
{
int ret = OB_SUCCESS;
dup_cnt = 0;
for (uint32_t i = 0; OB_SUCC(ret) && i < type_infos.count() - 1; ++i) {
int32_t pos = i + 1;
const ObString& cur_val = type_infos.at(i);
if (OB_FAIL(find_type(type_infos, cs_type, cur_val, pos))) {
LOG_WARN("fail to find type", K(type_infos), K(cur_val), K(pos));
} else if (OB_UNLIKELY(pos >= 0)) {
++dup_cnt;
if (is_strict_mode(sql_mode)) {
ret = OB_ER_DUPLICATED_VALUE_IN_TYPE;
LOG_USER_ERROR(OB_ER_DUPLICATED_VALUE_IN_TYPE,
col_name.length(),
col_name.ptr(),
cur_val.length(),
cur_val.ptr(),
ob_sql_type_str(col_type));
} else {
LOG_USER_WARN(OB_ER_DUPLICATED_VALUE_IN_TYPE,
col_name.length(),
col_name.ptr(),
cur_val.length(),
cur_val.ptr(),
ob_sql_type_str(col_type));
}
}
}
return ret;
}
int ObResolverUtils::check_max_val_count(ObObjType type, const ObString& col_name, int64_t val_cnt, int32_t dup_cnt)
{
int ret = OB_SUCCESS;
if (ObEnumType == type) {
if (val_cnt > OB_MAX_ENUM_ELEMENT_NUM) {
ret = OB_ER_TOO_BIG_ENUM;
LOG_USER_ERROR(OB_ER_TOO_BIG_ENUM, col_name.length(), col_name.ptr());
}
} else if (ObSetType == type) {
if (val_cnt - dup_cnt > OB_MAX_SET_ELEMENT_NUM) {
ret = OB_ERR_TOO_BIG_SET;
LOG_USER_ERROR(OB_ERR_TOO_BIG_SET, col_name.length(), col_name.ptr());
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected type", K(ret), K(val_cnt), K(dup_cnt));
}
return ret;
}
int ObResolverUtils::resolve_column_ref(
const ParseNode* node, const ObNameCaseMode case_mode, ObQualifiedName& column_ref)
{
int ret = OB_SUCCESS;
ParseNode* db_node = NULL;
ParseNode* relation_node = NULL;
ParseNode* column_node = NULL;
ObString column_name;
ObString table_name;
ObString database_name;
if (OB_ISNULL(node) || OB_UNLIKELY(node->type_ != T_COLUMN_REF)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("parse node is invalid", K(node));
} else {
db_node = node->children_[0];
relation_node = node->children_[1];
column_node = node->children_[2];
if (db_node != NULL) {
column_ref.database_name_.assign_ptr(
const_cast<char*>(db_node->str_value_), static_cast<int32_t>(db_node->str_len_));
}
}
if (OB_SUCC(ret)) {
if (relation_node != NULL) {
column_ref.tbl_name_.assign_ptr(
const_cast<char*>(relation_node->str_value_), static_cast<int32_t>(relation_node->str_len_));
}
if (OB_ISNULL(column_node)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("column node is null");
} else if (column_node->type_ == T_STAR) {
column_ref.is_star_ = true;
} else {
column_ref.is_star_ = false;
column_ref.col_name_.assign_ptr(
const_cast<char*>(column_node->str_value_), static_cast<int32_t>(column_node->str_len_));
}
}
if (OB_SUCC(ret) && share::is_mysql_mode() && OB_LOWERCASE_AND_INSENSITIVE == case_mode) {
ObCharset::casedn(CS_TYPE_UTF8MB4_GENERAL_CI, column_ref.database_name_);
ObCharset::casedn(CS_TYPE_UTF8MB4_GENERAL_CI, column_ref.tbl_name_);
}
return ret;
}
int ObResolverUtils::resolve_obj_access_ref_node(
ObRawExprFactory& expr_factory, const ParseNode* node, ObQualifiedName& q_name)
{
int ret = OB_SUCCESS;
// generate raw expr
if (OB_ISNULL(node)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null");
} else if (T_IDENT == node->type_ /*Mysql mode*/
|| T_COLUMN_REF == node->type_ /*Mysql mode*/) {
ObTimeZoneInfo tz_info;
ObNameCaseMode case_mode = OB_NAME_CASE_INVALID;
ObExprResolveContext ctx(expr_factory, &tz_info, case_mode);
ctx.session_info_ = NULL;
// ctx.is_oracle_compatible_ = (T_OBJ_ACCESS_REF == node->type_);
ObRawExprResolverImpl expr_resolver(ctx);
ObRawExpr* expr = NULL;
ObSEArray<ObQualifiedName, 1> columns;
ObArray<ObVarInfo> sys_vars;
ObArray<ObSubQueryInfo> sub_query_info;
ObArray<ObAggFunRawExpr*> aggr_exprs;
ObArray<ObWinFunRawExpr*> win_exprs;
ObArray<ObOpRawExpr*> op_exprs;
ObSEArray<ObUserVarIdentRawExpr*, 1> user_var_exprs;
if (OB_FAIL(expr_resolver.resolve(
node, expr, columns, sys_vars, sub_query_info, aggr_exprs, win_exprs, op_exprs, user_var_exprs))) {
LOG_WARN("failed to resolve expr tree", K(ret));
} else if (OB_UNLIKELY(1 != columns.count()) || OB_UNLIKELY(!sys_vars.empty()) ||
OB_UNLIKELY(!sub_query_info.empty()) || OB_UNLIKELY(!aggr_exprs.empty()) ||
OB_UNLIKELY(!win_exprs.empty())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is invalid",
K(op_exprs.empty()),
K(columns.count()),
K(sys_vars.count()),
K(sub_query_info.count()),
K(aggr_exprs.count()),
K(win_exprs.count()),
K(ret));
} else if (OB_FAIL(q_name.assign(columns.at(0)))) {
LOG_WARN("assign qualified name failed", K(ret), K(columns));
} else { /*do nothing*/
}
} else if (T_SYSTEM_VARIABLE == node->type_ || T_USER_VARIABLE_IDENTIFIER == node->type_) {
ObString access_name(node->str_len_, node->str_value_);
ObObjAccessIdent ident(access_name);
ret = q_name.access_idents_.push_back(ident);
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node type is invalid", K_(node->type));
}
return ret;
}
stmt::StmtType ObResolverUtils::get_stmt_type_by_item_type(const ObItemType item_type)
{
stmt::StmtType type;
switch (item_type) {
#define SET_STMT_TYPE(item_type) \
case item_type: { \
type = stmt::item_type; \
} break;
// dml
SET_STMT_TYPE(T_SELECT);
SET_STMT_TYPE(T_INSERT);
SET_STMT_TYPE(T_DELETE);
SET_STMT_TYPE(T_UPDATE);
SET_STMT_TYPE(T_REPLACE);
// ps
SET_STMT_TYPE(T_PREPARE);
SET_STMT_TYPE(T_EXECUTE);
SET_STMT_TYPE(T_DEALLOCATE);
// ddl
// tenant resource
SET_STMT_TYPE(T_CREATE_RESOURCE_POOL);
SET_STMT_TYPE(T_DROP_RESOURCE_POOL);
SET_STMT_TYPE(T_ALTER_RESOURCE_POOL);
SET_STMT_TYPE(T_SPLIT_RESOURCE_POOL);
SET_STMT_TYPE(T_MERGE_RESOURCE_POOL);
SET_STMT_TYPE(T_CREATE_RESOURCE_UNIT);
SET_STMT_TYPE(T_ALTER_RESOURCE_UNIT);
SET_STMT_TYPE(T_DROP_RESOURCE_UNIT);
SET_STMT_TYPE(T_CREATE_TENANT);
SET_STMT_TYPE(T_DROP_TENANT);
SET_STMT_TYPE(T_MODIFY_TENANT);
SET_STMT_TYPE(T_LOCK_TENANT);
// database
SET_STMT_TYPE(T_CREATE_DATABASE);
SET_STMT_TYPE(T_ALTER_DATABASE);
SET_STMT_TYPE(T_DROP_DATABASE);
// tablegroup
SET_STMT_TYPE(T_CREATE_TABLEGROUP);
SET_STMT_TYPE(T_ALTER_TABLEGROUP);
SET_STMT_TYPE(T_DROP_TABLEGROUP);
// table
SET_STMT_TYPE(T_CREATE_TABLE);
SET_STMT_TYPE(T_DROP_TABLE);
SET_STMT_TYPE(T_RENAME_TABLE);
SET_STMT_TYPE(T_TRUNCATE_TABLE);
SET_STMT_TYPE(T_CREATE_TABLE_LIKE);
SET_STMT_TYPE(T_ALTER_TABLE);
SET_STMT_TYPE(T_OPTIMIZE_TABLE);
SET_STMT_TYPE(T_OPTIMIZE_TENANT);
SET_STMT_TYPE(T_OPTIMIZE_ALL);
// view
SET_STMT_TYPE(T_CREATE_VIEW);
SET_STMT_TYPE(T_ALTER_VIEW);
SET_STMT_TYPE(T_DROP_VIEW);
// index
SET_STMT_TYPE(T_CREATE_INDEX);
SET_STMT_TYPE(T_DROP_INDEX);
// purge
SET_STMT_TYPE(T_PURGE_RECYCLEBIN);
SET_STMT_TYPE(T_PURGE_TENANT);
SET_STMT_TYPE(T_PURGE_DATABASE);
SET_STMT_TYPE(T_PURGE_TABLE);
SET_STMT_TYPE(T_PURGE_INDEX);
// outline
SET_STMT_TYPE(T_CREATE_OUTLINE);
SET_STMT_TYPE(T_ALTER_OUTLINE);
SET_STMT_TYPE(T_DROP_OUTLINE);
// synonym
SET_STMT_TYPE(T_CREATE_SYNONYM);
SET_STMT_TYPE(T_DROP_SYNONYM);
// variable set
SET_STMT_TYPE(T_VARIABLE_SET);
// plan baseline
SET_STMT_TYPE(T_ALTER_BASELINE);
// read only
SET_STMT_TYPE(T_EXPLAIN);
SET_STMT_TYPE(T_SHOW_COLUMNS);
SET_STMT_TYPE(T_SHOW_TABLES);
SET_STMT_TYPE(T_SHOW_DATABASES);
SET_STMT_TYPE(T_SHOW_TABLE_STATUS);
SET_STMT_TYPE(T_SHOW_SERVER_STATUS);
SET_STMT_TYPE(T_SHOW_VARIABLES);
SET_STMT_TYPE(T_SHOW_SCHEMA);
SET_STMT_TYPE(T_SHOW_CREATE_DATABASE);
SET_STMT_TYPE(T_SHOW_CREATE_TABLE);
SET_STMT_TYPE(T_SHOW_CREATE_VIEW);
SET_STMT_TYPE(T_SHOW_WARNINGS);
SET_STMT_TYPE(T_SHOW_ERRORS);
SET_STMT_TYPE(T_SHOW_GRANTS);
SET_STMT_TYPE(T_SHOW_CHARSET);
SET_STMT_TYPE(T_SHOW_COLLATION);
SET_STMT_TYPE(T_SHOW_PARAMETERS);
SET_STMT_TYPE(T_SHOW_INDEXES);
SET_STMT_TYPE(T_SHOW_PROCESSLIST);
SET_STMT_TYPE(T_SHOW_TABLEGROUPS);
SET_STMT_TYPE(T_SHOW_RECYCLEBIN);
SET_STMT_TYPE(T_SHOW_TENANT);
SET_STMT_TYPE(T_CREATE_SAVEPOINT);
SET_STMT_TYPE(T_RELEASE_SAVEPOINT);
SET_STMT_TYPE(T_ROLLBACK_SAVEPOINT);
#undef SET_STMT_TYPE
case T_ROLLBACK:
case T_COMMIT: {
type = stmt::T_END_TRANS;
} break;
case T_SP_CREATE_TYPE: {
type = stmt::T_CREATE_TYPE;
} break;
case T_SP_DROP_TYPE: {
type = stmt::T_DROP_TYPE;
} break;
// stored procedure
case T_SP_CREATE:
case T_SF_CREATE: {
type = stmt::T_CREATE_ROUTINE;
} break;
case T_SP_ALTER:
case T_SF_ALTER: {
type = stmt::T_ALTER_ROUTINE;
} break;
case T_SP_DROP:
case T_SF_DROP: {
type = stmt::T_DROP_ROUTINE;
} break;
// package
case T_PACKAGE_CREATE: {
type = stmt::T_CREATE_PACKAGE;
} break;
case T_PACKAGE_CREATE_BODY: {
type = stmt::T_CREATE_PACKAGE_BODY;
} break;
case T_PACKAGE_ALTER: {
type = stmt::T_ALTER_PACKAGE;
} break;
case T_PACKAGE_DROP: {
type = stmt::T_DROP_PACKAGE;
} break;
default: {
type = stmt::T_NONE;
} break;
}
return type;
}
int ObResolverUtils::resolve_stmt_type(const ParseResult& result, stmt::StmtType& type)
{
int ret = OB_SUCCESS;
CK(OB_NOT_NULL(result.result_tree_));
CK((T_STMT_LIST == result.result_tree_->type_));
CK((1 == result.result_tree_->num_child_));
CK(OB_NOT_NULL(result.result_tree_->children_[0]));
if (OB_SUCC(ret)) {
type = get_stmt_type_by_item_type(result.result_tree_->children_[0]->type_);
}
return ret;
}
int ObResolverUtils::resolve_const(const ParseNode* node, const stmt::StmtType stmt_type, ObIAllocator& allocator,
const ObCollationType connection_collation, const ObCollationType nchar_collation, const ObTimeZoneInfo* tz_info,
ObObjParam& val, const bool is_paramlize, common::ObString& literal_prefix,
const ObLengthSemantics default_length_semantics, const ObCollationType server_collation,
ObExprInfo* parents_expr_info)
{
UNUSED(stmt_type);
int ret = OB_SUCCESS;
if (OB_ISNULL(node) || OB_UNLIKELY(node->type_ < T_INVALID) || OB_UNLIKELY(node->type_ >= T_MAX_CONST)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("parse node is invalid", K(node));
} else {
LOG_DEBUG("resolve item", "item_type", get_type_name(static_cast<int>(node->type_)));
int16_t precision = PRECISION_UNKNOWN_YET;
int16_t scale = SCALE_UNKNOWN_YET;
// const value contains NOT_NULL flag
val.set_result_flag(OB_MYSQL_NOT_NULL_FLAG);
switch (node->type_) {
case T_HEX_STRING: {
ObString str_val;
str_val.assign_ptr(const_cast<char*>(node->str_value_), static_cast<int32_t>(node->str_len_));
val.set_hex_string(str_val);
val.set_collation_level(CS_LEVEL_COERCIBLE);
val.set_scale(0);
val.set_length(static_cast<int32_t>(node->str_len_));
val.set_param_meta(val.get_meta());
break;
}
case T_VARCHAR:
case T_CHAR:
case T_NVARCHAR2:
case T_NCHAR: {
if (lib::is_oracle_mode() && node->str_len_ == 0) {
val.set_null();
val.unset_result_flag(OB_MYSQL_NOT_NULL_FLAG);
val.set_length(0);
val.set_length_semantics(default_length_semantics);
ObObjMeta null_meta = ObObjMeta();
null_meta.set_collation_type(connection_collation);
null_meta.set_type(ObCharType);
null_meta.set_collation_level(CS_LEVEL_COERCIBLE);
val.set_param_meta(null_meta);
} else {
ObString str_val;
ObObj result_val;
str_val.assign_ptr(const_cast<char*>(node->str_value_), static_cast<int32_t>(node->str_len_));
val.set_string(static_cast<ObObjType>(node->type_), str_val);
// decide collation
/*
MySQL determines a literal's character set and collation in the following manner:
If both _X and COLLATE Y are specified, character set X and collation Y are used.
If _X is specified but COLLATE is not specified, character set X and its default collation
are used. To see the default collation for each character set, use the SHOW COLLATION statement.
Otherwise, the character set and collation given by the character_set_connection and
collation_connection system variables are used.
*/
val.set_collation_level(CS_LEVEL_COERCIBLE);
// TODO:: raw
// if (share::is_oracle_mode()) {
// val.set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset()));
// LOG_DEBUG("oracle use default cs_type", K(val), K(connection_collation));
// } else if (0 == node->num_child_) {
if (0 == node->num_child_) {
// for STRING without collation, e.g. show tables like STRING;
val.set_collation_type(connection_collation);
} else {
// STRING in SQL expression
ParseNode* charset_node = NULL;
if (NULL != node->children_[0] && T_CHARSET == node->children_[0]->type_) {
charset_node = node->children_[0];
}
if (NULL == charset_node) {
val.set_collation_type(connection_collation);
} else {
ObCharsetType charset_type = CHARSET_INVALID;
ObCollationType collation_type = CS_TYPE_INVALID;
if (charset_node != NULL) {
ObString charset(charset_node->str_len_, charset_node->str_value_);
if (CHARSET_INVALID == (charset_type = ObCharset::charset_type(charset.trim()))) {
ret = OB_ERR_UNKNOWN_CHARSET;
LOG_USER_ERROR(OB_ERR_UNKNOWN_CHARSET, charset.length(), charset.ptr());
} else {
// use the default collation of the specified charset
collation_type = ObCharset::get_default_collation(charset_type);
val.set_collation_type(collation_type);
LOG_DEBUG("use default collation", K(charset_type), K(collation_type));
ObLength length = static_cast<ObLength>(
ObCharset::strlen_char(val.get_collation_type(), val.get_string_ptr(), val.get_string_len()));
val.set_length(length);
if (OB_SUCC(ret) && OB_FAIL(ObSQLUtils::check_well_formed_str(val, result_val, true, true))) {
LOG_WARN("invalid str", K(ret), K(val));
}
}
}
}
}
ObLengthSemantics length_semantics = LS_DEFAULT;
if (OB_SUCC(ret)) {
if (T_NVARCHAR2 == node->type_ || T_NCHAR == node->type_) {
length_semantics = LS_CHAR;
} else {
length_semantics = default_length_semantics;
}
if (is_oracle_byte_length(share::is_oracle_mode(), length_semantics) && T_NVARCHAR2 != node->type_ &&
T_NCHAR != node->type_) {
val.set_length(val.get_string_len());
val.set_length_semantics(LS_BYTE);
} else {
ObLength length = static_cast<ObLength>(
ObCharset::strlen_char(val.get_collation_type(), val.get_string_ptr(), val.get_string_len()));
val.set_length(length);
val.set_length_semantics(LS_CHAR);
}
}
if (OB_SUCC(ret) && share::is_oracle_mode()) {
ObCollationType target_collation = CS_TYPE_INVALID;
if (T_NVARCHAR2 == node->type_ || T_NCHAR == node->type_) {
target_collation = nchar_collation;
} else {
target_collation = server_collation;
}
if (ObCharset::charset_type_by_coll(connection_collation) ==
ObCharset::charset_type_by_coll(target_collation)) {
val.set_collation_type(target_collation);
} else {
ObString str;
val.get_string(str);
char* buf = nullptr;
const int CharConvertFactorNum = 4;
int32_t buf_len = str.length() * CharConvertFactorNum;
uint32_t result_len = 0;
if (0 == buf_len) {
// do nothing
} else if (CS_TYPE_INVALID == target_collation) {
ret = OB_ERR_UNEXPECTED;
} else if (OB_UNLIKELY(nullptr == (buf = static_cast<char*>(allocator.alloc(buf_len))))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_ERROR("alloc memory failed", K(ret), K(buf_len));
} else {
ret = ObCharset::charset_convert(
connection_collation, str.ptr(), str.length(), target_collation, buf, buf_len, result_len);
if (OB_SUCCESS != ret) {
int32_t str_offset = 0;
int64_t buf_offset = 0;
ObString question_mark = ObCharsetUtils::get_const_str(target_collation, '?');
while (str_offset < str.length() && buf_offset + question_mark.length() <= buf_len) {
int64_t offset =
ObCharset::charpos(connection_collation, str.ptr() + str_offset, str.length() - str_offset, 1);
ret = ObCharset::charset_convert(connection_collation,
str.ptr() + str_offset,
offset,
target_collation,
buf + buf_offset,
buf_len - buf_offset,
result_len);
str_offset += offset;
if (OB_SUCCESS == ret) {
buf_offset += result_len;
} else {
MEMCPY(buf + buf_offset, question_mark.ptr(), question_mark.length());
buf_offset += question_mark.length();
}
}
if (str_offset < str.length()) {
ret = OB_SIZE_OVERFLOW;
LOG_WARN("size overflow", K(ret), K(str), KPHEX(str.ptr(), str.length()));
} else {
LOG_DEBUG("charset convert failed", K(ret), K(connection_collation), K(target_collation));
result_len = buf_offset;
ret = OB_SUCCESS;
}
}
if (OB_SUCC(ret)) {
val.set_string(val.get_type(), buf, static_cast<int32_t>(result_len));
val.set_collation_type(target_collation);
}
}
}
}
if (OB_SUCC(ret) && share::is_mysql_mode() &&
OB_FAIL(ObSQLUtils::check_well_formed_str(val, result_val, true, true))) {
LOG_WARN("invalid str", K(ret), K(val));
}
val.set_param_meta(val.get_meta());
}
LOG_DEBUG("resolve const char", K(val));
break;
}
case T_FLOAT:
case T_DOUBLE: {
int err = 0;
double value = 0;
char* endptr = NULL;
value = ObCharset::strntod(node->str_value_, static_cast<int32_t>(node->str_len_), &endptr, &err);
if (EOVERFLOW == err) {
ret = OB_NUMERIC_OVERFLOW;
literal_prefix.assign_ptr(node->str_value_, static_cast<int32_t>(node->str_len_));
LOG_WARN("float/double out of range", K(literal_prefix), K(ret));
} else {
if (T_DOUBLE == node->type_) {
val.set_double(value);
} else {
val.set_float(value);
}
val.set_length(static_cast<int16_t>(node->str_len_));
ObString tmp_input(static_cast<int32_t>(node->str_len_), node->str_value_);
if (lib::is_oracle_mode()) {
literal_prefix.assign_ptr(node->str_value_, static_cast<int32_t>(node->str_len_));
val.set_precision(PRECISION_UNKNOWN_YET);
val.set_scale(NUMBER_SCALE_UNKNOWN_YET);
if (val.is_double() ? (0 != isinf(val.get_double())) : (0 != isinff(val.get_float()))) {
ret = OB_NUMERIC_OVERFLOW;
LOG_WARN("float/double out of range", K(literal_prefix), K(val), K(ret));
}
}
_LOG_DEBUG("finish parse double from str, tmp_input=%.*s, value=%.30lf, ret=%d, type=%d, literal_prefix=%.*s",
tmp_input.length(),
tmp_input.ptr(),
value,
ret,
node->type_,
literal_prefix.length(),
literal_prefix.ptr());
}
val.set_param_meta(val.get_meta());
break;
}
case T_UINT64:
case T_INT: {
if (NULL != parents_expr_info) {
LOG_DEBUG("T_INT as pl acc idx", K(parents_expr_info->has_member(IS_PL_ACCESS_IDX)));
}
if (lib::is_oracle_mode() && NULL != node->str_value_ &&
(NULL == parents_expr_info || !parents_expr_info->has_member(IS_PL_ACCESS_IDX))) {
// go through as T_NUMBER
LOG_DEBUG("from int to number", K(node->str_value_), K(lbt()));
} else {
if (T_INT == node->type_) {
val.set_int(node->value_);
} else {
val.set_uint64(static_cast<uint64_t>(node->value_));
}
val.set_scale(0);
val.set_precision(static_cast<int16_t>(node->str_len_));
val.set_length(static_cast<int16_t>(node->str_len_));
val.set_param_meta(val.get_meta());
if (true == node->is_date_unit_) {
literal_prefix.assign_ptr(node->str_value_, static_cast<int32_t>(node->str_len_));
}
break;
}
}
case T_NUMBER: {
number::ObNumber nmb;
int16_t len = 0;
ObString tmp_string(static_cast<int32_t>(node->str_len_), node->str_value_);
if (NULL != tmp_string.find('e') || NULL != tmp_string.find('E')) {
ret = nmb.from_sci(node->str_value_, static_cast<int32_t>(node->str_len_), allocator, &precision, &scale);
len = static_cast<int16_t>(node->str_len_);
if (lib::is_oracle_mode()) {
literal_prefix.assign_ptr(node->str_value_, static_cast<int32_t>(node->str_len_));
}
} else {
ret = nmb.from(node->str_value_, static_cast<int32_t>(node->str_len_), allocator, &precision, &scale);
len = static_cast<int16_t>(node->str_len_);
}
if (OB_FAIL(ret)) {
if (OB_INTEGER_PRECISION_OVERFLOW == ret) {
LOG_WARN("integer presision overflow", K(ret));
} else if (OB_NUMERIC_OVERFLOW == ret) {
LOG_WARN("numeric overflow");
} else {
LOG_WARN("unexpected error", K(ret));
}
} else {
if (lib::is_oracle_mode()) {
precision = PRECISION_UNKNOWN_YET;
scale = NUMBER_SCALE_UNKNOWN_YET;
}
val.set_number(nmb);
val.set_precision(precision);
val.set_scale(scale);
val.set_length(len);
LOG_DEBUG("finish parse number from str", K(literal_prefix), K(nmb));
}
val.set_param_meta(val.get_meta());
break;
}
case T_NUMBER_FLOAT: {
number::ObNumber nmb;
if (OB_FAIL(nmb.from(node->str_value_, static_cast<int32_t>(node->str_len_), allocator, &precision, &scale))) {
if (OB_INTEGER_PRECISION_OVERFLOW == ret) {
LOG_WARN("integer presision overflow", K(ret));
} else if (OB_NUMERIC_OVERFLOW == ret) {
LOG_WARN("numeric overflow");
} else {
LOG_WARN("unexpected error", K(ret));
}
} else {
val.set_number(nmb);
val.set_precision(PRECISION_UNKNOWN_YET);
val.set_length(static_cast<int16_t>(node->str_len_));
}
val.set_param_meta(val.get_meta());
break;
}
case T_QUESTIONMARK: {
if (!is_paramlize) {
val.set_unknown(node->value_);
} else {
// used for sql concurrency control
val.set_int(0);
val.set_scale(0);
val.set_precision(1);
val.set_length(1);
}
val.set_param_meta(val.get_meta());
break;
}
case T_BOOL: {
val.set_bool(node->value_ == 1 ? true : false);
val.set_scale(0);
val.set_precision(1);
val.set_length(1);
val.set_param_meta(val.get_meta());
break;
}
case T_YEAR: {
ObString time_str(static_cast<int32_t>(node->str_len_), node->str_value_);
uint8_t time_val = 0;
if (OB_FAIL(ObTimeConverter::str_to_year(time_str, time_val))) {
LOG_WARN("fail to convert str to year", K(time_str), K(ret));
} else {
val.set_year(time_val);
val.set_scale(0);
val.set_param_meta(val.get_meta());
}
break;
}
case T_DATE: {
ObString time_str(static_cast<int32_t>(node->str_len_), node->str_value_);
int32_t time_val = 0;
if (OB_FAIL(ObTimeConverter::str_to_date(time_str, time_val))) {
ret = OB_ERR_WRONG_VALUE;
LOG_USER_ERROR(OB_ERR_WRONG_VALUE, "DATE", to_cstring(time_str));
} else {
val.set_date(time_val);
val.set_scale(0);
val.set_param_meta(val.get_meta());
}
break;
}
case T_TIME: {
ObString time_str(static_cast<int32_t>(node->str_len_), node->str_value_);
int64_t time_val = 0;
if (OB_FAIL(ObTimeConverter::str_to_time(time_str, time_val, &scale))) {
ret = OB_ERR_WRONG_VALUE;
LOG_USER_ERROR(OB_ERR_WRONG_VALUE, "TIME", to_cstring(time_str));
} else {
val.set_time(time_val);
val.set_scale(scale);
val.set_param_meta(val.get_meta());
}
break;
}
case T_DATETIME: {
ObString time_str(static_cast<int32_t>(node->str_len_), node->str_value_);
int64_t time_val = 0;
ObTimeConvertCtx cvrt_ctx(tz_info, false);
if (OB_FAIL(ObTimeConverter::literal_date_validate_oracle(time_str, cvrt_ctx, time_val))) {
LOG_WARN("fail to convert str to oracle date", K(time_str), K(ret));
} else {
val.set_datetime(time_val);
val.set_scale(OB_MAX_DATE_PRECISION);
literal_prefix = ObString::make_string(ORALCE_LITERAL_PREFIX_DATE);
val.set_param_meta(val.get_meta());
}
break;
}
case T_TIMESTAMP: {
ObString time_str(static_cast<int32_t>(node->str_len_), node->str_value_);
int64_t time_val = 0;
ObTimeConvertCtx cvrt_ctx(tz_info, false);
if (OB_FAIL(ObTimeConverter::str_to_datetime(time_str, cvrt_ctx, time_val, &scale))) {
ret = OB_ERR_WRONG_VALUE;
LOG_USER_ERROR(OB_ERR_WRONG_VALUE, "DATETIME", to_cstring(time_str));
} else {
val.set_datetime(time_val);
val.set_scale(scale);
val.set_param_meta(val.get_meta());
}
break;
}
case T_TIMESTAMP_TZ: {
ObObjType value_type = ObNullType;
ObOTimestampData tz_value;
ObTimeConvertCtx cvrt_ctx(tz_info, true);
ObString time_str(static_cast<int32_t>(node->str_len_), node->str_value_);
// if (OB_FAIL(ObTimeConverter::str_to_otimestamp(time_str, cvrt_ctx, tmp_type, ot_data))) {
if (OB_FAIL(ObTimeConverter::literal_timestamp_validate_oracle(time_str, cvrt_ctx, value_type, tz_value))) {
LOG_WARN("fail to str_to_otimestamp", K(time_str), K(ret));
} else {
/* use max scale bug:#18093350 */
val.set_otimestamp_value(value_type, tz_value);
val.set_scale(OB_MAX_TIMESTAMP_TZ_PRECISION);
literal_prefix = ObString::make_string(ORALCE_LITERAL_PREFIX_TIMESTAMP);
val.set_param_meta(val.get_meta());
}
break;
};
case T_INTERVAL_YM: {
char* tmp_ptr = NULL;
ObString tmp_str;
ObIntervalYMValue interval_value;
ObScale defined_scale;
ObString interval_str;
int16_t leading_precision = -1;
ObDateUnitType part_begin = DATE_UNIT_MAX;
ObDateUnitType part_end = DATE_UNIT_MAX;
ObValueChecker<int16_t> precision_checker(
0, MAX_SCALE_FOR_ORACLE_TEMPORAL, OB_ERR_DATETIME_INTERVAL_PRECISION_OUT_OF_RANGE);
literal_prefix.assign_ptr(node->raw_text_, static_cast<int32_t>(node->text_len_));
OZ(ob_dup_cstring(allocator, literal_prefix, tmp_ptr));
OX(tmp_str = ObString(tmp_ptr));
if (OB_SUCC(ret)) {
char* to_pos = strcasestr(tmp_ptr, "to");
if (OB_NOT_NULL(to_pos)) {
*to_pos = '\0';
OZ(parse_interval_ym_type(tmp_ptr, part_begin));
OZ(parse_interval_ym_type(to_pos + 1, part_end));
} else {
OZ(parse_interval_ym_type(tmp_ptr, part_begin));
part_end = part_begin;
}
}
OZ(parse_interval_precision(tmp_ptr, leading_precision, 2));
OZ(precision_checker.validate(leading_precision), leading_precision);
if (OB_SUCC(ret)) {
defined_scale = ObIntervalScaleUtil::interval_ym_scale_to_ob_scale(static_cast<int8_t>(leading_precision));
interval_str.assign_ptr(node->str_value_, static_cast<int32_t>(node->str_len_));
ObScale scale = defined_scale;
if (OB_FAIL(ObTimeConverter::literal_interval_ym_validate_oracle(
interval_str, interval_value, scale, part_begin, part_end))) {
LOG_WARN(
"fail to validate interval literal", K(ret), K(interval_str), K(part_begin), K(part_end), K(scale));
} else {
val.set_interval_ym(interval_value);
val.set_scale(defined_scale);
val.set_param_meta(val.get_meta());
}
}
LOG_DEBUG("interval year to month literal resolve", K(interval_str), K(literal_prefix));
break;
}
case T_INTERVAL_DS: {
char* tmp_ptr = NULL;
ObString tmp_str;
ObIntervalDSValue interval_value;
ObScale defined_scale;
ObString interval_str;
int16_t leading_precision = -1;
int16_t second_precision = -1;
ObDateUnitType part_begin = DATE_UNIT_MAX;
ObDateUnitType part_end = DATE_UNIT_MAX;
ObValueChecker<int16_t> precision_checker(
0, MAX_SCALE_FOR_ORACLE_TEMPORAL, OB_ERR_DATETIME_INTERVAL_PRECISION_OUT_OF_RANGE);
literal_prefix.assign_ptr(node->raw_text_, static_cast<int32_t>(node->text_len_));
OZ(ob_dup_cstring(allocator, literal_prefix, tmp_ptr));
OX(tmp_str = ObString(tmp_ptr));
if (OB_SUCC(ret)) {
char* to_pos = strcasestr(tmp_ptr, "to");
if (OB_NOT_NULL(to_pos)) { // interval 'xxx' day (x) to second (x)
*to_pos = '\0';
OZ(parse_interval_ds_type(tmp_ptr, part_begin));
OZ(parse_interval_precision(tmp_ptr, leading_precision, 2));
OZ(parse_interval_ds_type(to_pos + 1, part_end));
OZ(parse_interval_precision(to_pos + 1, second_precision, DATE_UNIT_SECOND == part_end ? 6 : 0));
} else { // interval 'xxx' day (x)
char* comma_pos = strchr(tmp_ptr, ',');
OZ(parse_interval_ds_type(tmp_ptr, part_begin));
part_end = part_begin;
if (OB_NOT_NULL(comma_pos)) { // interval 'xxx' second(x, x)
*comma_pos = ')';
OZ(parse_interval_precision(tmp_ptr, leading_precision, 2));
*comma_pos = '(';
OZ(parse_interval_precision(comma_pos, second_precision, 6));
} else {
OZ(parse_interval_precision(tmp_ptr, leading_precision, 2));
second_precision = DATE_UNIT_SECOND == part_end ? 6 : 0;
}
}
}
OZ(precision_checker.validate(leading_precision), leading_precision);
OZ(precision_checker.validate(second_precision), second_precision);
if (OB_SUCC(ret)) {
defined_scale = ObIntervalScaleUtil::interval_ds_scale_to_ob_scale(
static_cast<int8_t>(leading_precision), static_cast<int8_t>(second_precision));
interval_str.assign_ptr(node->str_value_, static_cast<int32_t>(node->str_len_));
ObScale scale = defined_scale;
if (OB_FAIL(ObTimeConverter::literal_interval_ds_validate_oracle(
interval_str, interval_value, scale, part_begin, part_end))) {
LOG_WARN(
"fail to validate interval literal", K(ret), K(interval_str), K(part_begin), K(part_end), K(scale));
} else {
val.set_interval_ds(interval_value);
val.set_scale(defined_scale);
val.set_param_meta(val.get_meta());
}
}
LOG_DEBUG("interval day to second literal resolve", K(interval_str), K(literal_prefix));
break;
}
case T_NULL: {
val.set_null();
val.unset_result_flag(OB_MYSQL_NOT_NULL_FLAG);
val.set_length(0);
val.set_param_meta(val.get_meta());
break;
}
default: {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("unknown item type here", K(ret), K(node->type_));
}
}
}
return ret;
}
int ObResolverUtils::resolve_timestamp_node(const bool is_set_null, const bool is_set_default,
const bool is_first_timestamp_column, ObSQLSessionInfo* session_info, ObColumnSchemaV2& column)
{
int ret = OB_SUCCESS;
// compatable for mysql
bool explicit_value = false;
if (OB_ISNULL(session_info)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("session info is NULL", K(ret));
} else if (OB_FAIL(session_info->get_explicit_defaults_for_timestamp(explicit_value))) {
LOG_WARN("fail to get explicit_defaults_for_timestamp", K(ret));
} else if (!explicit_value) {
if (is_first_timestamp_column && !is_set_null && !is_set_default && !column.is_on_update_current_timestamp()) {
column.set_nullable(false);
const_cast<ObObj*>(&column.get_cur_default_value())->set_ext(ObActionFlag::OP_DEFAULT_NOW_FLAG);
column.set_on_update_current_timestamp(true);
} else if (!is_set_null) {
column.set_nullable(false);
if (!is_set_default) {
if (is_no_zero_date(session_info->get_sql_mode())) {
ret = OB_INVALID_DEFAULT;
LOG_USER_ERROR(OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
} else {
const_cast<ObObj*>(&column.get_cur_default_value())->set_timestamp(ObTimeConverter::ZERO_DATETIME);
}
} else if (column.get_cur_default_value().is_null()) {
ret = OB_INVALID_DEFAULT;
LOG_USER_ERROR(OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
}
} else {
column.set_nullable(true);
if (!is_set_default) {
const_cast<ObObj*>(&column.get_cur_default_value())->set_null();
}
}
}
return ret;
}
int ObResolverUtils::add_column_ids_without_duplicate(const uint64_t column_id, common::ObIArray<uint64_t>* array)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(array) || OB_UNLIKELY(OB_INVALID_ID == column_id)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid arguemnt", K(array), K(column_id));
} else {
bool exist = false;
for (int64_t i = 0; !exist && i < array->count(); i++) {
if (array->at(i) == column_id) {
exist = true;
}
}
if (!exist) {
if (OB_FAIL(array->push_back(column_id))) {
LOG_WARN("fail to push back column id", K(ret));
}
}
}
return ret;
}
// for recursively process columns item in resolve_const_expr
// just wrap columns process logic in resolve_const_expr
int ObResolverUtils::resolve_columns_for_const_expr(
ObRawExpr*& expr, ObArray<ObQualifiedName>& columns, ObResolverParams& resolve_params)
{
int ret = OB_SUCCESS;
CK(OB_NOT_NULL(resolve_params.allocator_));
CK(OB_NOT_NULL(resolve_params.expr_factory_));
CK(OB_NOT_NULL(resolve_params.session_info_));
CK(OB_NOT_NULL(resolve_params.schema_checker_));
CK(OB_NOT_NULL(resolve_params.schema_checker_->get_schema_guard()));
// CK(OB_NOT_NULL(resolve_params.sql_proxy_));
ObArray<ObRawExpr*> real_exprs;
ObRawExpr* real_ref_expr = NULL;
for (int64_t i = 0; OB_SUCC(ret) && i < columns.count(); i++) {
ObQualifiedName& q_name = columns.at(i);
if (q_name.is_sys_func()) {
ObSysFunRawExpr* sys_func_expr = q_name.access_idents_.at(0).sys_func_expr_;
if (OB_ISNULL(sys_func_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("sys expr is null", K(ret));
} else if (OB_FAIL(sys_func_expr->check_param_num())) {
LOG_WARN("sys func check param failed", K(ret));
} else {
real_ref_expr = sys_func_expr;
}
} else {
// const expr can't use column
ret = OB_ERR_BAD_FIELD_ERROR;
ObString column_name = concat_qualified_name(q_name.database_name_, q_name.tbl_name_, q_name.col_name_);
ObString scope_name = ObString::make_string("field_list");
LOG_USER_ERROR(
OB_ERR_BAD_FIELD_ERROR, column_name.length(), column_name.ptr(), scope_name.length(), scope_name.ptr());
}
if (OB_SUCC(ret)) {
if (OB_FAIL(real_exprs.push_back(real_ref_expr))) {
LOG_WARN("push back error", K(ret));
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < real_exprs.count(); ++i) {
OZ(ObRawExprUtils::replace_ref_column(real_ref_expr, columns.at(i).ref_expr_, real_exprs.at(i)));
}
OZ(ObRawExprUtils::replace_ref_column(expr, q_name.ref_expr_, real_ref_expr));
}
return ret;
}
int ObResolverUtils::resolve_const_expr(
ObResolverParams& params, const ParseNode& node, ObRawExpr*& const_expr, ObIArray<ObVarInfo>* var_infos)
{
int ret = OB_SUCCESS;
ObArray<ObQualifiedName> columns;
ObArray<ObSubQueryInfo> sub_query_info;
ObArray<ObAggFunRawExpr*> aggr_exprs;
ObArray<ObWinFunRawExpr*> win_exprs;
ObArray<ObVarInfo> sys_vars;
ObArray<ObOpRawExpr*> op_exprs;
ObSEArray<ObUserVarIdentRawExpr*, 1> user_var_exprs;
ObCollationType collation_connection = CS_TYPE_INVALID;
ObCharsetType character_set_connection = CHARSET_INVALID;
if (OB_ISNULL(params.expr_factory_) || OB_ISNULL(params.session_info_)) {
ret = OB_NOT_INIT;
LOG_WARN("resolve status is invalid", K_(params.expr_factory), K_(params.session_info));
} else if (OB_FAIL(params.session_info_->get_collation_connection(collation_connection))) {
LOG_WARN("fail to get collation_connection", K(ret));
} else if (OB_FAIL(params.session_info_->get_character_set_connection(character_set_connection))) {
LOG_WARN("fail to get character_set_connection", K(ret));
} else {
ObExprResolveContext ctx(*params.expr_factory_, params.session_info_->get_timezone_info(), OB_NAME_CASE_INVALID);
ctx.dest_collation_ = collation_connection;
ctx.connection_charset_ = character_set_connection;
ctx.param_list_ = params.param_list_;
ctx.is_extract_param_type_ = !params.is_prepare_protocol_; // when prepare do not extract
ctx.schema_checker_ = params.schema_checker_;
ctx.session_info_ = params.session_info_;
ctx.query_ctx_ = params.query_ctx_;
ObRawExprResolverImpl expr_resolver(ctx);
if (OB_FAIL(params.session_info_->get_name_case_mode(ctx.case_mode_))) {
LOG_WARN("fail to get name case mode", K(ret));
} else if (OB_FAIL(expr_resolver.resolve(&node,
const_expr,
columns,
sys_vars,
sub_query_info,
aggr_exprs,
win_exprs,
op_exprs,
user_var_exprs))) {
LOG_WARN("resolve expr failed", K(ret));
} else if (OB_FAIL(resolve_columns_for_const_expr(const_expr, columns, params))) {
LOG_WARN("resolve columnts for const expr failed", K(ret));
} else if (sub_query_info.count() > 0) {
ret = OB_NOT_SUPPORTED;
LOG_USER_ERROR(OB_NOT_SUPPORTED, "subqueries or stored function calls here");
}
// process oracle compatible implicit conversion
if (OB_SUCC(ret) && op_exprs.count() > 0) {
LOG_WARN("impicit cast for oracle", K(ret));
if (OB_FAIL(ObRawExprUtils::resolve_op_exprs_for_oracle_implicit_cast(
ctx.expr_factory_, ctx.session_info_, op_exprs))) {
LOG_WARN("impicit cast failed", K(ret));
}
}
if (OB_SUCC(ret)) {
if (T_SP_CPARAM == const_expr->get_expr_type()) {
ret = OB_NOT_SUPPORTED;
LOG_USER_ERROR(OB_NOT_SUPPORTED, "call procedure");
} else {
OZ(const_expr->formalize(params.session_info_));
}
if (OB_SUCC(ret)) {
if (var_infos != NULL) {
if (ObRawExprUtils::merge_variables(sys_vars, *var_infos)) {
LOG_WARN("merge variables failed", K(ret));
}
} else {
params.prepare_param_count_ += ctx.prepare_param_count_; // prepare param count
}
}
}
}
return ret;
}
int ObResolverUtils::get_collation_type_of_names(
const ObSQLSessionInfo* session_info, const ObNameTypeClass type_class, ObCollationType& cs_type)
{
int ret = OB_SUCCESS;
ObNameCaseMode case_mode = OB_NAME_CASE_INVALID;
cs_type = CS_TYPE_INVALID;
if (share::is_mysql_mode()) {
if (OB_TABLE_NAME_CLASS == type_class) {
if (OB_ISNULL(session_info)) {
ret = OB_NOT_INIT;
LOG_WARN("session info is null");
} 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_ORIGIN_AND_SENSITIVE == case_mode) {
cs_type = CS_TYPE_UTF8MB4_BIN;
} else if (OB_ORIGIN_AND_INSENSITIVE == case_mode || OB_LOWERCASE_AND_INSENSITIVE == case_mode) {
cs_type = CS_TYPE_UTF8MB4_GENERAL_CI;
}
} else if (OB_COLUMN_NAME_CLASS == type_class) {
cs_type = CS_TYPE_UTF8MB4_GENERAL_CI;
} else if (OB_USER_NAME_CLASS == type_class) {
cs_type = CS_TYPE_UTF8MB4_BIN;
}
} else {
cs_type = CS_TYPE_UTF8MB4_BIN;
}
return ret;
}
int ObResolverUtils::name_case_cmp(const ObSQLSessionInfo* session_info, const ObString& name,
const ObString& name_other, const ObNameTypeClass type_class, bool& is_equal)
{
ObCollationType cs_type = CS_TYPE_INVALID;
int ret = OB_SUCCESS;
if (OB_FAIL(get_collation_type_of_names(session_info, type_class, cs_type))) {
LOG_WARN("fail to get collation type of name", K(name), K(name_other), K(type_class), K(ret));
} else if (0 == ObCharset::strcmp(cs_type, name, name_other)) {
is_equal = true;
} else {
is_equal = false;
}
return ret;
}
bool ObResolverUtils::is_valid_oracle_partition_data_type(const ObObjType data_type, const bool check_value)
{
bool bret = false;
switch (data_type) {
case ObIntType:
case ObFloatType:
case ObDoubleType:
case ObNumberType:
case ObDateTimeType:
case ObVarcharType:
case ObCharType:
case ObTimestampNanoType: {
bret = true;
break;
}
case ObTimestampType:
case ObTimestampLTZType: {
bret = !check_value;
break;
}
case ObTimestampTZType: {
bret = check_value;
break;
}
case ObRawType:
case ObIntervalYMType:
case ObIntervalDSType:
case ObNumberFloatType:
case ObNVarchar2Type:
case ObNCharType: {
bret = true;
break;
}
default: {
bret = false;
}
}
return bret;
}
bool ObResolverUtils::is_valid_partition_column_type(
const ObObjType type, const ObPartitionFuncType part_type, const bool is_check_value)
{
int bret = false;
if (PARTITION_FUNC_TYPE_HASH == part_type || PARTITION_FUNC_TYPE_HASH_V2 == part_type ||
PARTITION_FUNC_TYPE_RANGE == part_type || PARTITION_FUNC_TYPE_LIST == part_type) {
LOG_DEBUG("check partition column type", K(share::is_oracle_mode()), K(part_type), K(type), K(lbt()));
if (ob_is_integer_type(type) || ObYearType == type) {
bret = true;
} else if (share::is_oracle_mode() && is_valid_oracle_partition_data_type(type, is_check_value)) {
bret = true;
}
} else if (PARTITION_FUNC_TYPE_RANGE_COLUMNS == part_type || PARTITION_FUNC_TYPE_LIST_COLUMNS == part_type) {
if (share::is_oracle_mode()) {
if (is_valid_oracle_partition_data_type(type, is_check_value)) {
bret = true;
}
} else {
/**
* All integer types: TINYINT, SMALLINT, MEDIUMINT, INT (INTEGER), and BIGINT. (This is the same as with
* partitioning by RANGE and LIST.) Other numeric data types (such as DECIMAL or FLOAT) are not supported as
* partitioning columns. DATE and DATETIME. Columns using other data types relating to dates or times are not
* supported as partitioning columns. The following string types: CHAR, VARCHAR, BINARY, and VARBINARY. TEXT and
* BLOB columns are not supported as partitioning columns.
*/
// https://dev.mysql.com/doc/refman/5.7/en/partitioning-columns.html
ObObjTypeClass type_class = ob_obj_type_class(type);
if (ObIntTC == type_class || ObUIntTC == type_class || ObDateTimeTC == type_class || ObDateTC == type_class ||
ObStringTC == type_class || ObYearTC == type_class) {
bret = true;
}
}
}
return bret;
}
/* src_expr.type only can be int or number
restype only can be (unsigned tiny/smallint/int/bigint)
*/
int ObResolverUtils::try_convert_to_unsiged(const ObExprResType restype, ObRawExpr& src_expr, bool& is_out_of_range)
{
int ret = OB_SUCCESS;
ObCastCtx cast_ctx;
const ObObj& src = static_cast<sql::ObConstRawExpr*>(&src_expr)->get_value();
ObObj& result = static_cast<sql::ObConstRawExpr*>(&src_expr)->get_value();
is_out_of_range = true;
if (OB_FAIL(ObObjCaster::to_type(restype.get_type(), cast_ctx, src, result))) {
if (ret == OB_DATA_OUT_OF_RANGE) {
ret = OB_SUCCESS;
} else {
LOG_WARN("to type fail", K(restype), K(src_expr), K(ret));
}
} else {
is_out_of_range = false;
}
return ret;
}
int ObResolverUtils::check_partition_range_value_result_type(
const ObPartitionFuncType part_type, const ObColumnRefRawExpr& part_column_expr, ObRawExpr& part_value_expr)
{
int ret = OB_SUCCESS;
LOG_DEBUG("check_partition_range_value_result_type ", K(part_type), K(part_column_expr), K(part_value_expr));
ObObjTypeClass expect_value_tc = ObMaxTC;
bool need_cs_check = false;
const bool is_oracle_mode = share::is_oracle_mode();
ObObjType part_column_expr_type = part_column_expr.get_data_type();
switch (part_column_expr_type) {
case ObTinyIntType:
case ObSmallIntType:
case ObMediumIntType:
case ObInt32Type:
case ObIntType: {
expect_value_tc = ObIntTC;
need_cs_check = false;
break;
}
case ObUTinyIntType:
case ObUSmallIntType:
case ObUMediumIntType:
case ObUInt32Type:
case ObUInt64Type: {
expect_value_tc = ObUIntTC;
need_cs_check = false;
break;
}
case ObDateTimeType:
case ObDateType:
case ObTimeType:
case ObRawType:
case ObTimestampLTZType:
case ObTimestampNanoType: {
expect_value_tc = ObStringTC;
need_cs_check = true;
break;
}
case ObVarcharType:
case ObCharType:
case ObNVarchar2Type:
case ObNCharType: {
expect_value_tc = ObStringTC;
need_cs_check = true;
if (is_oracle_mode && CS_TYPE_UTF8MB4_GENERAL_CI == part_column_expr.get_collation_type()) {
ret = OB_NOT_SUPPORTED;
LOG_USER_ERROR(OB_NOT_SUPPORTED, "partition key with CS_TYPE_UTF8MB4_GENERAL_CI collation");
LOG_WARN("Partition key is string with CS_TYPE_UTF8MB4_GENERAL_CI", K(ret));
}
break;
}
case ObIntervalYMType:
case ObIntervalDSType: {
expect_value_tc = ob_obj_type_class(part_column_expr_type);
break;
}
case ObFloatType:
case ObDoubleType: {
if (is_oracle_mode) {
expect_value_tc = ObStringTC;
break;
}
}
case ObNumberType:
case ObNumberFloatType: {
if (is_oracle_mode) {
expect_value_tc = ObNumberTC;
break;
}
}
default: {
ret = OB_ERR_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD;
LOG_USER_ERROR(OB_ERR_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD,
part_column_expr.get_column_name().length(),
part_column_expr.get_column_name().ptr());
LOG_WARN("Field is not a allowed type for this type of partitioning", K(ret), K(part_column_expr_type));
}
}
UNUSED(need_cs_check);
if (OB_SUCC(ret)) {
ObObjType part_value_expr_type = part_value_expr.get_data_type();
ObObjTypeClass part_value_expr_tc = part_value_expr.get_type_class();
if (part_value_expr_tc != expect_value_tc || ObTimestampLTZType == part_column_expr_type) {
bool is_allow = false;
if (ObNullTC == part_value_expr_tc && PARTITION_FUNC_TYPE_LIST_COLUMNS == part_type) {
is_allow = true;
} else if (is_oracle_mode) {
switch (part_column_expr_type) {
case ObFloatType:
case ObDoubleType:
case ObNumberFloatType:
case ObNumberType: {
is_allow = (ObStringTC == part_value_expr_tc ||
(ObIntTC <= part_value_expr_tc && part_value_expr_tc <= ObNumberTC));
break;
}
case ObDateTimeType:
case ObTimestampNanoType: {
is_allow = (ObDateTimeType == part_value_expr_type || ObTimestampNanoType == part_value_expr_type ||
ObTimestampTZType == part_value_expr_type);
break;
}
case ObTimestampLTZType: {
is_allow = (ObTimestampTZType == part_value_expr_type);
break;
}
case ObVarcharType:
case ObCharType:
case ObNVarchar2Type:
case ObNCharType: {
is_allow = true;
break;
}
default: {
break;
}
}
} else {
bool is_out_of_range = true;
/* for mysql mode only (siged -> unsigned ) */
if (part_value_expr.is_const_expr() && (part_value_expr_tc == ObIntTC || part_value_expr_tc == ObNumberTC) &&
expect_value_tc == ObUIntTC) {
if (OB_FAIL(try_convert_to_unsiged(part_column_expr.get_result_type(), part_value_expr, is_out_of_range))) {
LOG_WARN("check const range fail", K(ret));
} else {
is_allow = (is_out_of_range == false);
}
}
}
if (OB_SUCC(ret) && !is_allow) {
ret = (ObTimestampLTZType == part_column_expr_type ? OB_ERR_WRONG_TIMESTAMP_LTZ_COLUMN_VALUE_ERROR
: OB_ERR_WRONG_TYPE_COLUMN_VALUE_ERROR);
LOG_WARN("object type is invalid ",
K(ret),
K(expect_value_tc),
K(part_value_expr_tc),
K(part_column_expr_type),
K(part_value_expr_type));
}
}
}
return ret;
}
int ObResolverUtils::check_valid_column_for_hash_or_range(
const ObRawExpr& part_expr, const ObPartitionFuncType part_func_type)
{
int ret = OB_SUCCESS;
if (part_expr.is_column_ref_expr()) {
const ObColumnRefRawExpr& column_ref = static_cast<const ObColumnRefRawExpr&>(part_expr);
if (!is_valid_partition_column_type(column_ref.get_data_type(), part_func_type, false)) {
ret = OB_ERR_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD;
LOG_USER_ERROR(OB_ERR_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD,
column_ref.get_column_name().length(),
column_ref.get_column_name().ptr());
LOG_WARN("Field is not a allowed type for this type of partitioning", K(ret), "type", column_ref.get_data_type());
}
} else {
if (PARTITION_FUNC_TYPE_RANGE_COLUMNS == part_func_type || PARTITION_FUNC_TYPE_LIST_COLUMNS == part_func_type) {
ret = OB_ERR_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD;
LOG_WARN("partition by range columns should be column_ref expr", K(ret));
}
}
return ret;
}
int ObResolverUtils::check_partition_value_expr_for_range(const ObString& part_name, const ObRawExpr& part_func_expr,
ObRawExpr& part_value_expr, const ObPartitionFuncType part_type, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
if (OB_SUCC(ret)) {
bool gen_col_check = false;
bool accept_charset_function = in_tablegroup;
ObRawExprPartFuncChecker part_func_checker(gen_col_check, accept_charset_function);
if (OB_FAIL(part_value_expr.preorder_accept(part_func_checker))) {
if (lib::is_oracle_mode() && OB_ERR_PARTITION_FUNCTION_IS_NOT_ALLOWED == ret) {
ret = (share::schema::is_list_part(part_type) ? OB_ERR_WRONG_TYPE_COLUMN_VALUE_V2_ERROR
: OB_ERR_WRONG_TYPE_COLUMN_VALUE_ERROR);
}
LOG_WARN("check partition function failed", K(ret));
}
}
if (OB_SUCC(ret)) {
if (PARTITION_FUNC_TYPE_RANGE == part_type || PARTITION_FUNC_TYPE_LIST == part_type) {
ObObjType value_type = part_value_expr.get_data_type();
if (share::is_oracle_mode() && is_valid_oracle_partition_data_type(value_type, true)) {
// oracle mode support int/numeric/datetime/timestamp/string/raw
} else if (share::is_mysql_mode() && ob_is_integer_type(value_type)) {
// iin partition by range(xx) partition p0 values less than (expr), expr would always be integer
} else if (ObNullTC == part_value_expr.get_type_class() && PARTITION_FUNC_TYPE_LIST == part_type) {
// do nothing
} else {
ret = OB_ERR_VALUES_IS_NOT_INT_TYPE_ERROR;
LOG_USER_ERROR(OB_ERR_VALUES_IS_NOT_INT_TYPE_ERROR, part_name.length(), part_name.ptr());
LOG_WARN("part_value_expr type is not correct",
K(ret),
"data_type",
part_value_expr.get_data_type(),
K(share::is_oracle_mode()),
K(share::is_mysql_mode()));
}
} else if (PARTITION_FUNC_TYPE_RANGE_COLUMNS == part_type || PARTITION_FUNC_TYPE_LIST_COLUMNS == part_type) {
if (!part_func_expr.is_column_ref_expr()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition by range columns() should be column expr", K(ret), "type", part_func_expr.get_expr_type());
} else {
const ObColumnRefRawExpr& column_ref = static_cast<const ObColumnRefRawExpr&>(part_func_expr);
if (OB_FAIL(check_partition_range_value_result_type(part_type, column_ref, part_value_expr))) {
LOG_WARN("get partition range value result type failed", K(ret), K(part_name));
}
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected partition type", K(ret), K(part_type));
}
}
return ret;
}
int ObResolverUtils::check_partition_value_expr_for_range(const ObString& part_name, ObRawExpr& part_value_expr,
const ObPartitionFuncType part_type, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
if (OB_SUCC(ret)) {
bool gen_col_check = false;
bool accept_charset_function = in_tablegroup;
ObRawExprPartFuncChecker part_func_checker(gen_col_check, accept_charset_function);
if (OB_FAIL(part_value_expr.preorder_accept(part_func_checker))) {
LOG_WARN("check partition function failed", K(ret));
}
}
if (OB_SUCC(ret)) {
if (PARTITION_FUNC_TYPE_RANGE == part_type || PARTITION_FUNC_TYPE_LIST == part_type) {
// partition by range(xx) partition p0 values less than (expr): expr is always integer
if (!ob_is_integer_type(part_value_expr.get_data_type())) {
ret = OB_ERR_VALUES_IS_NOT_INT_TYPE_ERROR;
LOG_USER_ERROR(OB_ERR_VALUES_IS_NOT_INT_TYPE_ERROR, part_name.length(), part_name.ptr());
LOG_WARN("part_value_expr type is not correct", K(ret), "date_type", part_value_expr.get_data_type());
}
} else if (PARTITION_FUNC_TYPE_RANGE_COLUMNS == part_type || PARTITION_FUNC_TYPE_LIST_COLUMNS == part_type) {
const ObObjType value_type = part_value_expr.get_data_type();
if (!is_valid_partition_column_type(value_type, part_type, true)) {
ret = OB_ERR_WRONG_TYPE_COLUMN_VALUE_ERROR;
LOG_USER_ERROR(OB_ERR_WRONG_TYPE_COLUMN_VALUE_ERROR);
LOG_WARN("object type is invalid ", K(ret), K(value_type));
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected partition type", K(ret), K(part_type));
}
}
return ret;
}
int ObResolverUtils::check_partition_expr_for_oracle_hash(
ObRawExpr& expr, const ObPartitionFuncType part_type, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
UNUSED(in_tablegroup);
if (T_FUN_SYS_PART_HASH_V1 != expr.get_expr_type() && T_FUN_SYS_PART_HASH_V2 != expr.get_expr_type()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition func should be T_FUN_SYS_PART_HASH_V1 or T_FUN_SYS_PART_HASH_V2 ", K(ret), K(expr));
}
for (int64_t i = 0; OB_SUCC(ret) && i < expr.get_param_count(); ++i) {
ObRawExpr* param_expr = expr.get_param_expr(i);
if (OB_ISNULL(param_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("param expr should not be null", K(ret));
} else if (OB_FAIL(check_valid_column_for_hash_or_range(*param_expr, part_type))) {
LOG_WARN("chck_valid_column_for_hash_func failed", K(ret));
} else if (ObVarcharType == param_expr->get_data_type() || ObCharType == param_expr->get_data_type() ||
ob_is_nstring_type(param_expr->get_data_type())) {
if (CS_TYPE_UTF8MB4_GENERAL_CI == param_expr->get_collation_type()) {
ret = OB_NOT_SUPPORTED;
LOG_USER_ERROR(OB_NOT_SUPPORTED, "Partition key with CS_TYPE_UTF8MB4_GENERAL_CI");
LOG_WARN("Partition key is string with CS_TYPE_UTF8MB4_GENERAL_CI", K(ret));
}
}
}
return ret;
}
int ObResolverUtils::check_partition_expr_for_hash_or_range(
ObRawExpr& expr, const ObPartitionFuncType part_type, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
ObRawExpr* part_expr = NULL;
LOG_DEBUG("check_partition_expr_for_hash_or_range", K(ret), K(expr), K(part_type), K(in_tablegroup));
if (is_hash_part(part_type)) {
if (expr.get_param_count() != 1 ||
(T_FUN_SYS_PART_HASH_V1 != expr.get_expr_type() && T_FUN_SYS_PART_HASH_V2 != expr.get_expr_type())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("param count of hash func should be 1",
K(ret),
"param count",
expr.get_param_count(),
"expr type",
expr.get_expr_type());
} else {
part_expr = expr.get_param_expr(0);
}
} else if (is_range_part(part_type) || is_list_part(part_type)) {
part_expr = &expr;
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition type is invalid", K(ret));
}
if (OB_SUCC(ret)) {
if (OB_ISNULL(part_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("part expr should not be null", K(ret));
} else if (OB_FAIL(check_valid_column_for_hash_or_range(*part_expr, part_type))) {
LOG_WARN("chck_valid_column_for_hash_func failed", K(ret));
} else {
bool gen_col_check = false;
bool accept_charset_function = in_tablegroup;
ObRawExprPartFuncChecker part_func_checker(gen_col_check, accept_charset_function);
if (OB_FAIL(part_expr->preorder_accept(part_func_checker))) {
LOG_WARN("check partition function failed", K(ret));
}
}
if (OB_SUCC(ret)) {
ObRawExprPartExprChecker part_expr_checker;
if (OB_FAIL(part_expr->preorder_accept(part_expr_checker))) {
LOG_WARN("check_part_expr failed", K(ret));
}
}
}
return ret;
}
// "index + view" combination
// fill depend/base table to RS for sync version
int ObResolverUtils::update_materialized_view_schema(
const ObMaterializedViewContext& ctx, ObSchemaChecker& schema_checker, ObTableSchema& view_schema)
{
int ret = OB_SUCCESS;
view_schema.set_table_type(MATERIALIZED_VIEW);
view_schema.set_index_type(INDEX_TYPE_NORMAL_LOCAL);
view_schema.set_data_table_id(ctx.base_table_id_);
ret = view_schema.add_base_table_id(ctx.base_table_id_);
if (OB_SUCC(ret)) {
ret = view_schema.add_depend_table_id(ctx.depend_table_id_);
}
if (OB_SUCC(ret)) {
const uint64_t base_table_id = ctx.base_table_id_;
const ObTableSchema* base_table_schema = NULL;
if (OB_FAIL(schema_checker.get_table_schema(base_table_id, base_table_schema))) {
LOG_WARN("get table schema failed", K(ret), K(base_table_id));
} else if (OB_ISNULL(base_table_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(base_table_schema), K(base_table_id));
} else {
// keep properties same as base table
view_schema.set_block_size(base_table_schema->get_block_size());
view_schema.set_read_only(base_table_schema->is_read_only());
view_schema.set_progressive_merge_num(base_table_schema->get_progressive_merge_num());
view_schema.set_tablet_size(base_table_schema->get_tablet_size());
view_schema.set_collation_type(base_table_schema->get_collation_type());
view_schema.set_pctfree(base_table_schema->get_pctfree());
view_schema.set_row_store_type(base_table_schema->get_row_store_type());
view_schema.set_store_format(base_table_schema->get_store_format());
view_schema.set_storage_format_version(base_table_schema->get_storage_format_version());
if (OB_FAIL(view_schema.set_compress_func_name(base_table_schema->get_compress_func_name()))) {
LOG_WARN("set_compress_func_name failed", K(*base_table_schema));
}
}
}
return ret;
}
// check column_name duplicate with select_column_name
// if duplicated, generate a new colume name with format:
// __mv_col_$1_$2_$3 % (table_id, column_id, old_column_name)
int ObResolverUtils::check_and_generate_column_name(const ObMaterializedViewContext& ctx, char* buf,
const int64_t buf_len, const uint64_t table_id, const uint64_t column_id, const ObString& col_name,
ObString& new_col_name)
{
int ret = OB_SUCCESS;
new_col_name.reset();
if (OB_ISNULL(buf) || buf_len <= 0) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("buf is invalid", K(ret), K(buf), K(buf_len));
} else {
ObColumnRefRawExpr* dup_expr = NULL;
for (int64_t i = 0; NULL == dup_expr && OB_SUCC(ret) && i < ctx.select_cols_.count(); ++i) {
ObColumnRefRawExpr* col_expr = ctx.select_cols_.at(i);
if (OB_ISNULL(col_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(col_expr));
} else {
if (col_expr->get_table_id() == table_id && col_expr->get_column_id() == column_id) {
dup_expr = col_expr;
}
}
}
if (OB_SUCC(ret)) {
if (NULL != dup_expr) {
new_col_name =
dup_expr->get_alias_column_name().empty() ? dup_expr->get_column_name() : dup_expr->get_alias_column_name();
} else {
new_col_name = col_name;
while (OB_SUCC(ret)) {
bool same_as = false;
for (int64_t i = 0; !same_as && OB_SUCC(ret) && i < ctx.select_cols_.count(); ++i) {
const ObColumnRefRawExpr* col_expr = ctx.select_cols_.at(i);
if (OB_ISNULL(col_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(col_expr));
} else {
const ObString& cur_col_name = col_expr->get_alias_column_name().empty()
? col_expr->get_column_name()
: col_expr->get_alias_column_name();
same_as = ObCharset::case_insensitive_equal(cur_col_name, new_col_name);
}
}
if (OB_SUCC(ret)) {
if (!same_as) {
break;
} else {
int64_t n = snprintf(buf,
buf_len,
"__mv_col_%lu_%lu_%.*s",
table_id,
column_id,
new_col_name.length(),
new_col_name.ptr());
if (n <= 0 || n >= buf_len) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("snprintf failed", K(n), K(buf_len));
} else {
new_col_name.assign_ptr(buf, static_cast<int32_t>(n));
}
}
}
}
}
}
}
LOG_INFO("new column name", K(new_col_name));
return ret;
}
// generate materialized view schema
// rowkey: order by cols + base table's rowkey cols
// normal cols: depend table's rowkey cols + base table's join cols
int ObResolverUtils::make_columns_for_materialized_view(
const ObMaterializedViewContext& ctx, ObSchemaChecker& schema_checker, ObTableSchema& view_schema)
{
int ret = OB_SUCCESS;
LOG_INFO("dump mv without columns", K(view_schema));
const uint64_t base_table_id = ctx.base_table_id_;
const uint64_t depend_table_id = ctx.depend_table_id_;
const ObTableSchema* base_table_schema = NULL;
const ObTableSchema* depend_table_schema = NULL;
if (OB_FAIL(schema_checker.get_table_schema(base_table_id, base_table_schema))) {
LOG_WARN("get table schema failed", K(ret), K(base_table_id));
} else if (OB_FAIL(schema_checker.get_table_schema(depend_table_id, depend_table_schema))) {
LOG_WARN("get table schema failed", K(ret), K(depend_table_id));
} else if (OB_ISNULL(base_table_schema) || OB_ISNULL(depend_table_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(base_table_schema), K(depend_table_schema));
} else {
const int64_t buf_len = OB_MAX_COLUMN_NAME_BUF_LENGTH;
char buf[buf_len];
// rowkey: order by cols
for (int64_t i = 0; i < ctx.order_cols_.count(); ++i) {
ObColumnRefRawExpr* col_expr = ctx.order_cols_.at(i);
if (OB_ISNULL(col_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(col_expr));
} else {
ObString col_name =
col_expr->get_alias_column_name().empty() ? col_expr->get_column_name() : col_expr->get_alias_column_name();
ObString new_col_name;
if (NULL != view_schema.get_column_schema(col_expr->get_column_id())) {
// do-nothing
} else if (OB_FAIL(check_and_generate_column_name(ctx,
buf,
buf_len,
col_expr->get_table_id(),
col_expr->get_column_id(),
col_name,
new_col_name))) {
LOG_WARN("check and gen column name failed",
K(ret),
K(col_expr->get_table_id()),
K(col_expr->get_column_id()),
K(col_name));
} else if (OB_FAIL(add_column_for_schema(*base_table_schema,
col_expr->get_column_id(),
col_expr->get_column_id(),
new_col_name,
true,
view_schema))) {
LOG_WARN("fail to add column", K(ret), K(col_expr->get_column_id()), K(new_col_name));
}
}
}
// rowkey: base table's rowkey cols
// normal cols: depend table's rowkey cols
if (OB_SUCC(ret)) {
for (int64_t i = 0; OB_SUCC(ret) && i < 2; ++i) {
const bool is_base_table = 0 == i;
const ObTableSchema* table_schema = is_base_table ? base_table_schema : depend_table_schema;
const uint64_t table_id = is_base_table ? base_table_id : depend_table_id;
const ObRowkeyInfo& rowkey_info = table_schema->get_rowkey_info();
for (int64_t j = 0; OB_SUCC(ret) && j < rowkey_info.get_size(); ++j) {
uint64_t column_id = 0;
const ObColumnSchemaV2* col_schema = NULL;
if (OB_FAIL(rowkey_info.get_column_id(j, column_id))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("fail to get rowkey info", K(ret), K(j), K(rowkey_info));
} else if (NULL == (col_schema = table_schema->get_column_schema(column_id))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(column_id));
} else {
uint64_t new_column_id = column_id;
ObString new_col_name;
if (!is_base_table) {
new_column_id = view_schema.gen_materialized_view_column_id(column_id);
}
if (NULL != view_schema.get_column_schema(new_column_id)) {
// do-nothing
} else if (OB_FAIL(check_and_generate_column_name(
ctx, buf, buf_len, table_id, column_id, col_schema->get_column_name_str(), new_col_name))) {
LOG_WARN("check and gen column name failed",
K(ret),
K(table_id),
K(column_id),
K(col_schema->get_column_name_str()));
} else if (OB_FAIL(add_column_for_schema(
*table_schema, column_id, new_column_id, new_col_name, is_base_table, view_schema))) {
LOG_WARN("fail to add column", K(ret), K(column_id), K(new_column_id), K(new_col_name), K(is_base_table));
}
}
}
}
}
// normal cols: base table's cols in join condition:
if (OB_SUCC(ret)) {
for (int64_t i = 0; i < ctx.base_join_cols_.count(); ++i) {
ObColumnRefRawExpr* col_expr = ctx.base_join_cols_.at(i);
if (OB_ISNULL(col_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(col_expr));
} else {
ObString col_name = col_expr->get_alias_column_name().empty() ? col_expr->get_column_name()
: col_expr->get_alias_column_name();
ObString new_col_name;
if (NULL != view_schema.get_column_schema(col_expr->get_column_id())) {
// do-nothing
} else if (OB_FAIL(check_and_generate_column_name(ctx,
buf,
buf_len,
col_expr->get_table_id(),
col_expr->get_column_id(),
col_name,
new_col_name))) {
LOG_WARN("check and gen column name failed",
K(ret),
K(col_expr->get_table_id()),
K(col_expr->get_column_id()),
K(col_name));
} else if (OB_FAIL(add_column_for_schema(*base_table_schema,
col_expr->get_column_id(),
col_expr->get_column_id(),
new_col_name,
false,
view_schema))) {
LOG_WARN("fail to add column", K(ret), K(col_expr->get_column_id()), K(new_col_name));
}
}
}
}
// normal cols: select cols
if (OB_SUCC(ret)) {
for (int64_t i = 0; OB_SUCC(ret) && i < 2; ++i) {
const bool is_base_table = 0 == i;
const ObTableSchema* table_schema = is_base_table ? base_table_schema : depend_table_schema;
const ObIArray<ObColumnRefRawExpr*>& col_exprs =
is_base_table ? ctx.base_select_cols_ : ctx.depend_select_cols_;
for (int64_t j = 0; j < col_exprs.count() && OB_SUCC(ret); ++j) {
ObColumnRefRawExpr* col_expr = col_exprs.at(j);
if (OB_ISNULL(col_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(col_expr));
} else {
ObString col_name = col_expr->get_alias_column_name().empty() ? col_expr->get_column_name()
: col_expr->get_alias_column_name();
const uint64_t column_id = col_expr->get_column_id();
uint64_t new_column_id = column_id;
if (!is_base_table) {
new_column_id = view_schema.gen_materialized_view_column_id(column_id);
}
if (NULL != view_schema.get_column_schema(new_column_id)) {
// do-nothing
} else if (NULL != view_schema.get_column_schema(col_name)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(col_name));
} else if (OB_FAIL(add_column_for_schema(
*table_schema, column_id, new_column_id, col_name, false, view_schema))) {
LOG_WARN("fail to add column",
K(ret),
K(table_schema->get_table_id()),
K(column_id),
K(new_column_id),
K(col_name));
}
}
}
}
}
}
return ret;
}
int ObResolverUtils::make_columns_for_cte_view(const ObMaterializedViewContext& ctx, ObSchemaChecker& schema_checker,
ObTableSchema& view_schema, common::ObArray<ObString> cte_col_names)
{
int ret = OB_SUCCESS;
LOG_INFO("dump mv without columns", K(view_schema));
const uint64_t base_table_id = ctx.base_table_id_;
const uint64_t depend_table_id = ctx.depend_table_id_;
const ObTableSchema* base_table_schema = NULL;
const ObTableSchema* depend_table_schema = NULL;
if (OB_FAIL(schema_checker.get_table_schema(base_table_id, base_table_schema))) {
LOG_WARN("get table schema failed", K(ret), K(base_table_id));
} else if (OB_FAIL(schema_checker.get_table_schema(depend_table_id, depend_table_schema))) {
LOG_WARN("get table schema failed", K(ret), K(depend_table_id));
} else if (OB_ISNULL(base_table_schema) || OB_ISNULL(depend_table_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(base_table_schema), K(depend_table_schema));
} else {
// const int64_t buf_len = OB_MAX_COLUMN_NAME_LENGTH;
// char buf[buf_len];
// rowkey: order by cols
for (int64_t i = 0; i < ctx.order_cols_.count(); ++i) {}
// rowkey: base table's rowkey cols
// normal cols: depend table's rowkey cols
if (OB_SUCC(ret)) {
for (int64_t i = 0; OB_SUCC(ret) && i < 2; ++i) {}
}
// normal cols: base table's cols in join condition:
if (OB_SUCC(ret)) {
for (int64_t i = 0; i < ctx.base_join_cols_.count(); ++i) {}
}
// normal cols: select cols
if (OB_SUCC(ret)) {
for (int64_t i = 0; OB_SUCC(ret) && i < 2; ++i) {
const bool is_base_table = 0 == i;
const ObTableSchema* table_schema = is_base_table ? base_table_schema : depend_table_schema;
const ObIArray<ObColumnRefRawExpr*>& col_exprs =
is_base_table ? ctx.base_select_cols_ : ctx.depend_select_cols_;
if (col_exprs.count() != cte_col_names.count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cte define column num does not match the select item nums from left query");
}
for (int64_t j = 0; j < col_exprs.count() && OB_SUCC(ret); ++j) {
ObColumnRefRawExpr* col_expr = col_exprs.at(j);
if (OB_ISNULL(col_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(col_expr));
} else {
ObString col_name = col_expr->get_alias_column_name().empty() ? col_expr->get_column_name()
: col_expr->get_alias_column_name();
const uint64_t column_id = col_expr->get_column_id();
uint64_t new_column_id = column_id;
if (!is_base_table) {
new_column_id = view_schema.gen_materialized_view_column_id(column_id);
}
if (NULL != view_schema.get_column_schema(new_column_id)) {
// do-nothing
} else if (NULL != view_schema.get_column_schema(col_name)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(col_name));
} else if (OB_FAIL(add_column_for_schema(
*table_schema, column_id, new_column_id, col_name, false, view_schema))) {
LOG_WARN("fail to add column",
K(ret),
K(table_schema->get_table_id()),
K(column_id),
K(new_column_id),
K(col_name));
}
}
}
}
}
}
return ret;
}
#if 0
int ObResolverUtils::find_base_and_depend_table(ObSchemaChecker &schema_checker,
ObSelectStmt &stmt,
uint64_t &base_table_id,
uint64_t &depend_table_id,
ObIArray<ObColumnRefRawExpr *> &base_table_cols,
ObIArray<ObColumnRefRawExpr *> &depend_table_cols)
{
int ret = OB_SUCCESS;
return ret;
}
#endif
int ObResolverUtils::find_base_and_depend_table(
ObSchemaChecker& schema_checker, ObSelectStmt& stmt, ObMaterializedViewContext& ctx)
{
int ret = OB_SUCCESS;
ctx.base_table_id_ = OB_INVALID_ID;
ctx.depend_table_id_ = OB_INVALID_ID;
ctx.base_join_cols_.reset();
ctx.depend_join_cols_.reset();
TableItem* l_tbl = NULL;
TableItem* r_tbl = NULL;
ObArray<ObRawExpr*> join_exprs;
int64_t from_item_size = stmt.get_from_item_size();
if (from_item_size <= 0 || from_item_size > 2) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("unsupported table refrence", K(ret), K(from_item_size));
} else if (1 == from_item_size) {
if (stmt.get_joined_tables().count() != 1) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("unsupported table refrence", K(ret), K(stmt.get_joined_tables().count()));
} else {
JoinedTable* join_tbl = stmt.get_joined_tables().at(0);
if (join_tbl->joined_type_ != INNER_JOIN) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("unsuported table refrence", K(join_tbl->joined_type_), K(ret));
} else {
l_tbl = join_tbl->left_table_;
r_tbl = join_tbl->right_table_;
for (int64_t i = 0; i < join_tbl->join_conditions_.count(); ++i) {
ret = join_exprs.push_back(join_tbl->join_conditions_.at(i));
}
}
}
} else {
if (stmt.get_from_item(0).is_joined_ || stmt.get_from_item(1).is_joined_) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("unsupported table refrence",
K(ret),
K(stmt.get_from_item(0).is_joined_),
K(stmt.get_from_item(1).is_joined_));
} else if (stmt.get_table_size() != 2) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("unsupported table refrence", K(ret), K(stmt.get_table_size()));
} else {
l_tbl = stmt.get_table_item(0);
r_tbl = stmt.get_table_item(1);
}
}
if (OB_SUCC(ret)) {
if (OB_ISNULL(l_tbl) || OB_ISNULL(r_tbl)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(l_tbl), K(r_tbl), K(ret));
} else if (!l_tbl->is_basic_table() || !r_tbl->is_basic_table()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("unsupported table refrence", K(l_tbl->is_basic_table()), K(r_tbl->is_basic_table()), K(ret));
} else if (TableItem::ALIAS_TABLE == l_tbl->type_ || TableItem::ALIAS_TABLE == r_tbl->type_) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("unsupported table refrence", K(l_tbl->type_), K(r_tbl->type_), K(ret));
}
}
if (OB_SUCC(ret)) {
for (int64_t i = 0; OB_SUCC(ret) && i < stmt.get_condition_exprs().count(); ++i) {
ret = join_exprs.push_back(stmt.get_condition_exprs().at(i));
}
}
if (OB_SUCC(ret)) {
LOG_INFO("table items", K(*l_tbl), K(*r_tbl));
LOG_INFO("join conditions", K(join_exprs));
}
if (OB_SUCC(ret)) {
const uint64_t l_tbl_id = l_tbl->table_id_;
const uint64_t r_tbl_id = r_tbl->table_id_;
ObArray<ObColumnRefRawExpr*> l_tbl_cols;
ObArray<ObColumnRefRawExpr*> r_tbl_cols;
for (int64_t i = 0; OB_SUCC(ret) && i < join_exprs.count(); ++i) {
ObRawExpr* expr = join_exprs.at(i);
if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(expr), K(ret));
} else if (expr->get_expr_type() != T_OP_EQ) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("unsupported join condition", K(expr->get_expr_type()), K(ret));
} else {
ObColumnRefRawExpr* l_col = NULL;
ObColumnRefRawExpr* r_col = NULL;
for (int64_t j = 0; OB_SUCC(ret) && j < 2; ++j) {
ObRawExpr* param_expr = expr->get_param_expr(j);
if (OB_ISNULL(param_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(param_expr), K(ret));
} else if (!param_expr->is_column_ref_expr()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("only basic column ref allowed in join condition", K(ret), "type", param_expr->get_expr_type());
} else {
ObColumnRefRawExpr*& e = 0 == j ? l_col : r_col;
e = static_cast<ObColumnRefRawExpr*>(param_expr);
}
}
if (OB_SUCC(ret)) {
if (OB_ISNULL(l_col) || OB_ISNULL(r_col)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(l_col), K(r_col), K(ret));
} else if (l_col->get_table_id() == r_col->get_table_id()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN(
"join condition's table should differ", K(l_col->get_table_id()), K(r_col->get_table_id()), K(ret));
} else if (!((l_col->get_table_id() == l_tbl_id && r_col->get_table_id() == r_tbl_id) ||
(l_col->get_table_id() == r_tbl_id && r_col->get_table_id() == l_tbl_id))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected join condition's column",
K(l_tbl_id),
K(r_tbl_id),
K(l_col->get_table_id()),
K(r_col->get_table_id()),
K(ret));
} else {
if (l_col->get_table_id() == l_tbl_id) {
ret = l_tbl_cols.push_back(l_col);
if (OB_SUCC(ret)) {
ret = r_tbl_cols.push_back(r_col);
}
} else {
ret = r_tbl_cols.push_back(l_col);
if (OB_SUCC(ret)) {
ret = l_tbl_cols.push_back(r_col);
}
}
}
}
}
}
if (OB_SUCC(ret)) {
if (l_tbl_cols.count() != r_tbl_cols.count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected error", K(l_tbl_cols.count()), K(r_tbl_cols.count()), K(ret));
} else {
bool l_candi = false;
bool r_candi = false;
const ObTableSchema* l_tbl_schema = NULL;
const ObTableSchema* r_tbl_schema = NULL;
if (OB_FAIL(schema_checker.get_table_schema(l_tbl_id, l_tbl_schema))) {
LOG_WARN("unexpected error", K(ret), K(l_tbl_id));
} else if (OB_FAIL(schema_checker.get_table_schema(r_tbl_id, r_tbl_schema))) {
LOG_WARN("unexpected error", K(ret), K(r_tbl_id));
} else if (OB_ISNULL(l_tbl_schema) || OB_ISNULL(r_tbl_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(l_tbl_schema), K(r_tbl_schema), K(ret));
} else {
// check pk col cover join condition
bool l_cover = false;
bool r_cover = false;
for (int64_t i = 0; OB_SUCC(ret) && i < 2; ++i) {
const ObTableSchema* tbl = 0 == i ? l_tbl_schema : r_tbl_schema;
const ObArray<ObColumnRefRawExpr*>& tbl_cols = 0 == i ? l_tbl_cols : r_tbl_cols;
const ObRowkeyInfo& rowkey_info = tbl->get_rowkey_info();
bool cover = true;
for (int64_t j = 0; cover && OB_SUCC(ret) && j < rowkey_info.get_size(); ++j) {
uint64_t rowkey_column_id = 0;
if (OB_FAIL(rowkey_info.get_column_id(j, rowkey_column_id))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("fail to get rowkey info", K(ret), K(j), K(rowkey_info));
} else {
bool has = false;
for (int64_t k = 0; !has && OB_SUCC(ret) && k < tbl_cols.count(); ++k) {
has = rowkey_column_id == tbl_cols.at(k)->get_column_id();
}
if (OB_SUCC(ret)) {
if (!has) {
cover = false;
}
}
}
}
if (OB_SUCC(ret)) {
if (cover) {
if (0 == i) {
l_cover = true;
} else {
r_cover = true;
}
}
}
}
bool l_cover_r = false;
bool r_cover_r = false;
// check join condition cover pk col
for (int64_t i = 0; OB_SUCC(ret) && i < 2; ++i) {
const ObTableSchema* tbl = 0 == i ? l_tbl_schema : r_tbl_schema;
const ObArray<ObColumnRefRawExpr*>& tbl_cols = 0 == i ? l_tbl_cols : r_tbl_cols;
bool cover = true;
for (int64_t j = 0; cover && OB_SUCC(ret) && j < tbl_cols.count(); ++j) {
const ObRowkeyInfo& rowkey_info = tbl->get_rowkey_info();
bool is_rowkey_col = false;
if (OB_FAIL(rowkey_info.is_rowkey_column(tbl_cols.at(j)->get_column_id(), is_rowkey_col))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN(
"check is rowkey info failed", K(ret), K(j), K(tbl_cols.at(j)->get_column_id()), K(rowkey_info));
} else if (!is_rowkey_col) {
cover = false;
}
}
if (OB_SUCC(ret)) {
if (cover) {
if (0 == i) {
l_cover_r = true;
} else {
r_cover_r = true;
}
}
}
}
if (OB_SUCC(ret)) {
bool l_is = false;
bool r_is = false;
if (OB_FAIL(schema_checker.check_is_all_server_readonly_replica(l_tbl_schema->get_table_id(), l_is))) {
LOG_WARN("fail to check", K(ret));
} else if (OB_FAIL(
schema_checker.check_is_all_server_readonly_replica(r_tbl_schema->get_table_id(), r_is))) {
LOG_WARN("fail to check", K(ret));
} else {
l_candi = l_cover && l_cover_r && l_is;
r_candi = r_cover && r_cover_r && r_is;
}
LOG_INFO("cover info", K(ret), K(l_cover), K(l_cover_r), K(l_is), K(r_cover), K(r_cover_r), K(r_is));
}
}
if (OB_SUCC(ret)) {
if (!l_candi && !r_candi) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("no depend table candidates", K(ret));
} else if (!l_candi) {
ctx.depend_table_id_ = r_tbl_id;
ctx.base_table_id_ = l_tbl_id;
ctx.depend_join_cols_ = r_tbl_cols;
ctx.base_join_cols_ = l_tbl_cols;
} else {
ctx.depend_table_id_ = l_tbl_id;
ctx.base_table_id_ = r_tbl_id;
ctx.depend_join_cols_ = l_tbl_cols;
ctx.base_join_cols_ = r_tbl_cols;
}
}
if (OB_SUCC(ret)) {
LOG_INFO("table info", K(ctx));
}
if (OB_SUCC(ret)) {
if (!l_candi && !r_candi) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("no depend table candidates", K(ret));
} else if (!l_candi) {
ctx.depend_table_id_ = r_tbl_id;
ctx.base_table_id_ = l_tbl_id;
ctx.depend_join_cols_ = r_tbl_cols;
ctx.base_join_cols_ = l_tbl_cols;
} else {
ctx.depend_table_id_ = l_tbl_id;
ctx.base_table_id_ = r_tbl_id;
ctx.depend_join_cols_ = l_tbl_cols;
ctx.base_join_cols_ = r_tbl_cols;
}
}
if (OB_SUCC(ret)) {
LOG_INFO("table info", K(ctx));
}
}
}
}
if (OB_SUCC(ret)) {
const uint64_t depend_tbl_id = ctx.depend_table_id_;
const ObTableSchema* depend_tbl_schema = NULL;
if (OB_FAIL(schema_checker.get_table_schema(depend_tbl_id, depend_tbl_schema))) {
LOG_WARN("unexpected error", K(ret), K(depend_tbl_id));
} else if (OB_ISNULL(depend_tbl_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(depend_tbl_schema), K(depend_tbl_id), K(ret));
} else if (depend_tbl_schema->get_part_level() != PARTITION_LEVEL_ZERO) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("depend table must be non-partitioned table",
K(depend_tbl_id),
K(depend_tbl_schema->get_part_level()),
K(ret));
}
}
return ret;
}
// limitation:
int ObResolverUtils::check_materialized_view_limitation(ObSelectStmt& stmt, ObMaterializedViewContext& ctx)
{
int ret = OB_SUCCESS;
// 1. forbiden same projection name
// 2. forbiden same ref column
for (int64_t i = 0; OB_SUCC(ret) && i < stmt.get_select_item_size(); ++i) {
ObRawExpr* expr = stmt.get_select_item(i).expr_;
if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(expr));
} else if (!expr->is_column_ref_expr()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected", K(ret), K(expr->get_expr_type()));
} else {
ObColumnRefRawExpr* select_expr = static_cast<ObColumnRefRawExpr*>(expr);
const ObString& select_name = !select_expr->get_alias_column_name().empty() ? select_expr->get_alias_column_name()
: select_expr->get_column_name();
for (int64_t j = i + 1; OB_SUCC(ret) && j < stmt.get_select_item_size(); j++) {
ObRawExpr* oth_expr = stmt.get_select_item(j).expr_;
if (OB_ISNULL(oth_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(oth_expr));
} else if (!oth_expr->is_column_ref_expr()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected", K(ret), K(oth_expr->get_expr_type()));
} else {
ObColumnRefRawExpr* oth_select_expr = static_cast<ObColumnRefRawExpr*>(oth_expr);
const ObString& oth_select_name = !oth_select_expr->get_alias_column_name().empty()
? oth_select_expr->get_alias_column_name()
: oth_select_expr->get_column_name();
if (ObCharset::case_insensitive_equal(select_name, oth_select_name)) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("unsupport same projection name", K(ret), K(select_name), K(oth_select_name));
} else if (select_expr->get_table_id() == oth_select_expr->get_table_id() &&
select_expr->get_column_id() == oth_select_expr->get_column_id()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("unsupport same column ref",
K(ret),
K(select_expr->get_table_id()),
K(oth_select_expr->get_table_id()),
K(select_expr->get_column_id()),
K(oth_select_expr->get_column_id()));
}
}
}
if (OB_SUCC(ret)) {
if (select_expr->get_table_id() == ctx.base_table_id_) {
ret = ctx.base_select_cols_.push_back(select_expr);
} else if (select_expr->get_table_id() == ctx.depend_table_id_) {
ret = ctx.depend_select_cols_.push_back(select_expr);
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected table id", K(ret), K(ctx.depend_table_id_), K(select_expr->get_table_id()));
}
if (OB_SUCC(ret)) {
ret = ctx.select_cols_.push_back(select_expr);
}
}
}
}
// L1: must one partition table: 'base table'
if (OB_SUCC(ret)) {
int64_t n_part_exprs = stmt.get_part_exprs().count();
if (n_part_exprs > 1) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("at most one partition table support", K(ret), "current is", n_part_exprs);
}
}
if (OB_INVALID_ID == ctx.base_table_id_ || OB_INVALID_ID == ctx.depend_table_id_) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("base/depend table must be exist", K(ret), K(ctx.base_table_id_), K(ctx.depend_table_id_));
}
// L2: order by must be:
// - nake column
// - from base table
// - exist in select item
// - order direction must be ASC
if (OB_SUCC(ret)) {
const ObIArray<OrderItem>& order_items = stmt.get_order_items();
for (int64_t i = 0; i < order_items.count() && OB_SUCC(ret); i++) {
const OrderItem& order_item = order_items.at(i);
if (!order_item.expr_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null expr", K(ret));
} else if (!order_item.expr_->is_column_ref_expr()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("order by item must be nake column", K(ret), "expr", order_item.expr_);
} else if (is_descending_direction(order_item.order_type_)) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("order direction must be asc", K(ret));
} else {
ObColumnRefRawExpr* col_ref = static_cast<ObColumnRefRawExpr*>(order_item.expr_);
if (col_ref->get_table_id() != ctx.base_table_id_) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("order by columns must be from base table",
K(ret),
"base table_id",
ctx.base_table_id_,
"conflict table_id",
col_ref->get_table_id());
} else {
ret = ctx.order_cols_.push_back(col_ref);
}
}
} // for
}
// L3: join type must be inner join
if (OB_SUCC(ret)) {
for (int64_t i = 0; i < stmt.get_joined_tables().count() && OB_SUCC(ret); i++) {
const JoinedTable* join = stmt.get_joined_tables().at(i);
if (!join) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("join table is null", K(ret));
} else if (join->joined_type_ != INNER_JOIN) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("only inner join supported", K(ret));
}
}
}
// left and right column of join condition must have same collation
if (OB_SUCC(ret)) {
if (ctx.base_join_cols_.count() != ctx.depend_join_cols_.count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("join cols must be equal", K(ret), K(ctx.base_join_cols_.count()), K(ctx.depend_join_cols_.count()));
}
for (int64_t i = 0; OB_SUCC(ret) && i < ctx.base_join_cols_.count(); ++i) {
ObColumnRefRawExpr* base_col = ctx.base_join_cols_.at(i);
ObColumnRefRawExpr* depend_col = ctx.depend_join_cols_.at(i);
if (OB_ISNULL(base_col) || OB_ISNULL(depend_col)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(base_col), K(depend_col));
} else if (base_col->get_collation_type() != depend_col->get_collation_type()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN(
"left and right column of join condition must have same collation", K(ret), K(*base_col), K(*depend_col));
}
}
}
// L4: no limit
if (OB_SUCC(ret)) {
if (stmt.get_limit_expr()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support for limit", K(ret));
}
}
// L5: no union/intersect/except
if (OB_SUCC(ret)) {
if (ObSelectStmt::NONE != stmt.get_set_op()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support for set", K(ret));
}
}
// L6: no rownum / aggr
LOG_INFO("mv info", K(ctx));
return ret;
}
//
// update necessary info for column before add to schema
//
int ObResolverUtils::add_column_for_schema(const ObTableSchema& ori_table, const uint64_t ori_col_id,
const uint64_t new_col_id, const ObString& new_col_name, const bool is_rowkey, ObTableSchema& view_schema)
{
int ret = OB_SUCCESS;
const ObColumnSchemaV2* col = ori_table.get_column_schema(ori_col_id);
if (OB_ISNULL(col)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(col));
} else {
ObColumnSchemaV2 column = *col;
column.set_tenant_id(view_schema.get_tenant_id());
column.set_table_id(view_schema.get_table_id());
column.set_column_id(new_col_id);
column.set_column_name(new_col_name);
if (is_rowkey) {
int64_t rowkey_pos = view_schema.get_rowkey_column_num();
column.set_rowkey_position(++rowkey_pos);
view_schema.set_rowkey_column_num(rowkey_pos);
} else {
column.set_rowkey_position(0);
}
column.set_schema_version(view_schema.get_schema_version());
if (OB_FAIL(view_schema.add_column(column))) {
LOG_WARN("fail to add column for view schema", K(ret), K(column));
} else {
LOG_INFO("dump mv column",
"ori table_id",
ori_table.get_table_id(),
"ori column_id",
ori_col_id,
"ori column_name",
col->get_column_name_str(),
"new table_id",
view_schema.get_table_id(),
"new column_id",
new_col_id,
"new column_name",
new_col_name,
K(is_rowkey),
K(column));
}
}
return ret;
}
int ObResolverUtils::fill_table_ids_for_mv(ObSelectStmt* select_stmt, ObSchemaChecker* schema_checker)
{
int ret = OB_SUCCESS;
for (uint64_t i = 0; i < select_stmt->get_table_size() && OB_SUCC(ret); i++) {
bool has_all_server_readonly_replica = false;
uint64_t table_id = select_stmt->get_table_item(i)->ref_id_;
if (OB_FAIL(schema_checker->check_has_all_server_readonly_replica(table_id, has_all_server_readonly_replica))) {
LOG_WARN("fail to check has all server readonly replica", K(table_id), K(ret));
} else {
if (has_all_server_readonly_replica) {
select_stmt->set_depend_table_id(table_id);
} else {
select_stmt->set_base_table_id(table_id);
}
}
}
return ret;
}
int ObResolverUtils::log_err_msg_for_partition_value(const ObQualifiedName& name)
{
int ret = OB_SUCCESS;
if (!name.tbl_name_.empty() && !name.col_name_.empty()) {
ret = OB_ERR_UNKNOWN_TABLE;
if (!name.database_name_.empty()) {
LOG_USER_ERROR(OB_ERR_UNKNOWN_TABLE,
name.tbl_name_.length(),
name.tbl_name_.ptr(),
name.database_name_.length(),
name.database_name_.ptr());
} else {
ObString scope_name("partition function");
LOG_USER_ERROR(
OB_ERR_UNKNOWN_TABLE, name.tbl_name_.length(), name.tbl_name_.ptr(), scope_name.length(), scope_name.ptr());
}
LOG_WARN("unknown table in partition function", K(name));
} else if (!name.col_name_.empty()) {
ret = OB_ERR_BAD_FIELD_ERROR;
ObString scope_name("partition function");
LOG_USER_ERROR(
OB_ERR_BAD_FIELD_ERROR, name.col_name_.length(), name.col_name_.ptr(), scope_name.length(), scope_name.ptr());
} else if (!name.access_idents_.empty()) {
const ObString& func_name = name.access_idents_.at(name.access_idents_.count() - 1).access_name_;
ret = OB_ERR_FUNCTION_UNKNOWN;
LOG_WARN("Invalid function name in partition function", K(name.access_idents_.count()), K(ret), K(func_name));
LOG_USER_ERROR(OB_ERR_FUNCTION_UNKNOWN, func_name.length(), func_name.ptr());
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("name is invalid", K(name), K(ret));
}
return ret;
}
int ObResolverUtils::resolve_partition_list_value_expr(ObResolverParams& params, const ParseNode& node,
const ObString& part_name, const ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
ObIArray<ObRawExpr*>& part_value_expr_array, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
if (node.type_ == T_EXPR_LIST) {
if (node.num_child_ != part_func_exprs.count()) {
ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
LOG_WARN("Inconsistency in usage of column lists for partitioning near",
K(ret),
"node_child_num",
node.num_child_,
"part_func_expr",
part_func_exprs.count());
}
for (int64_t i = 0; OB_SUCC(ret) && i < node.num_child_; i++) {
ObRawExpr* part_value_expr = NULL;
ObRawExpr* part_func_expr = NULL;
if (OB_FAIL(part_func_exprs.at(i, part_func_expr))) {
LOG_WARN("get part expr failed", K(i), "size", part_func_exprs.count(), K(ret));
} else if (OB_ISNULL(part_func_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("part_func_expr is invalid", K(ret));
} else if (OB_FAIL(ObResolverUtils::resolve_partition_range_value_expr(params,
*(node.children_[i]),
part_name,
part_type,
*part_func_expr,
part_value_expr,
in_tablegroup))) {
LOG_WARN("resolve partition expr failed", K(ret));
} else if (OB_FAIL(part_value_expr_array.push_back(part_value_expr))) {
LOG_WARN("array push back fail", K(ret));
} else {
}
}
} else {
ObRawExpr* part_value_expr = NULL;
ObRawExpr* part_func_expr = NULL;
if (OB_FAIL(part_func_exprs.at(0, part_func_expr))) {
LOG_WARN("get part expr failed", "size", part_func_exprs.count(), K(ret));
} else if (OB_ISNULL(part_func_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("part_func_expr is invalid", K(ret));
} else if (OB_FAIL(ObResolverUtils::resolve_partition_range_value_expr(
params, node, part_name, part_type, *part_func_expr, part_value_expr, in_tablegroup))) {
LOG_WARN("resolve partition expr failed", K(ret));
} else if (OB_FAIL(part_value_expr_array.push_back(part_value_expr))) {
LOG_WARN("array push back fail", K(ret));
} else {
}
}
return ret;
}
int ObResolverUtils::resolve_partition_range_value_expr(ObResolverParams& params, const ParseNode& node,
const ObString& part_name, const ObPartitionFuncType part_type, const ObRawExpr& part_func_expr,
ObRawExpr*& part_value_expr, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
ObCollationType collation_connection = CS_TYPE_INVALID;
ObCharsetType character_set_connection = CHARSET_INVALID;
if (part_name.empty() && !lib::is_oracle_mode()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("part name is invalid", K(ret), K(part_name));
} else if (OB_ISNULL(params.expr_factory_) || OB_ISNULL(params.session_info_)) {
ret = OB_NOT_INIT;
LOG_WARN("resolve status is invalid", K_(params.expr_factory), K_(params.session_info));
} else if (OB_FAIL(params.session_info_->get_collation_connection(collation_connection))) {
LOG_WARN("fail to get collation_connection", K(ret));
} else if (OB_FAIL(params.session_info_->get_character_set_connection(character_set_connection))) {
LOG_WARN("fail to get character_set_connection", K(ret));
} else {
ObArray<ObQualifiedName> columns;
ObArray<ObSubQueryInfo> sub_query_info;
ObArray<ObVarInfo> sys_vars;
ObArray<ObAggFunRawExpr*> aggr_exprs;
ObArray<ObWinFunRawExpr*> win_exprs;
ObArray<ObColumnRefRawExpr*> part_column_refs;
ObArray<ObOpRawExpr*> op_exprs;
ObSEArray<ObUserVarIdentRawExpr*, 1> user_var_exprs;
ObExprResolveContext ctx(*params.expr_factory_, params.session_info_->get_timezone_info(), OB_NAME_CASE_INVALID);
ctx.dest_collation_ = collation_connection;
ctx.connection_charset_ = ObCharset::charset_type_by_coll(part_func_expr.get_collation_type());
ctx.param_list_ = params.param_list_;
ctx.session_info_ = params.session_info_;
ctx.query_ctx_ = params.query_ctx_;
ObRawExprResolverImpl expr_resolver(ctx);
if (OB_FAIL(params.session_info_->get_name_case_mode(ctx.case_mode_))) {
LOG_WARN("fail to get name case mode", K(ret));
} else if (OB_FAIL(expr_resolver.resolve(&node,
part_value_expr,
columns,
sys_vars,
sub_query_info,
aggr_exprs,
win_exprs,
op_exprs,
user_var_exprs))) {
LOG_WARN("resolve expr failed", K(ret));
} else if (sub_query_info.count() > 0) {
ret = OB_ERR_PARTITION_FUNCTION_IS_NOT_ALLOWED;
} else if (OB_FAIL(resolve_columns_for_partition_range_value_expr(part_value_expr, columns))) {
LOG_WARN("resolve columns failed", K(ret));
}
if (OB_SUCC(ret)) {
if (OB_ISNULL(part_value_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("part expr should not be null", K(ret));
} else if (OB_FAIL(part_value_expr->formalize(params.session_info_))) {
LOG_WARN("formailize expr failed", K(ret));
} else if (OB_FAIL(check_partition_value_expr_for_range(
part_name, part_func_expr, *part_value_expr, part_type, in_tablegroup))) {
LOG_WARN("check_valid_column_for_hash or range func failed", K(part_type), K(part_name), K(ret));
} else {
LOG_DEBUG("succ to check_partition_value_expr_for_range",
K(part_type),
K(part_name),
K(part_func_expr),
KPC(part_value_expr),
K(ret));
}
}
}
return ret;
}
int ObResolverUtils::resolve_partition_list_value_expr(ObResolverParams& params, const ParseNode& node,
const ObString& part_name, const ObPartitionFuncType part_type, int64_t& expr_num,
ObIArray<ObRawExpr*>& part_value_expr_array, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
if (node.type_ == T_EXPR_LIST) {
if (OB_INVALID_COUNT != expr_num && node.num_child_ != expr_num) {
ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
LOG_WARN("Inconsistency in usage of column lists for partitioning near",
K(ret),
K(expr_num),
"child_num",
node.num_child_);
} else {
expr_num = node.num_child_;
}
for (int64_t i = 0; OB_SUCC(ret) && i < node.num_child_; i++) {
ObRawExpr* part_value_expr = NULL;
if (OB_FAIL(ObResolverUtils::resolve_partition_range_value_expr(
params, *(node.children_[i]), part_name, part_type, part_value_expr, in_tablegroup))) {
LOG_WARN("resolve partition expr failed", K(ret));
} else if (OB_FAIL(part_value_expr_array.push_back(part_value_expr))) {
LOG_WARN("array push back fail", K(ret));
}
}
} else {
expr_num = 1;
ObRawExpr* part_value_expr = NULL;
if (OB_FAIL(ObResolverUtils::resolve_partition_range_value_expr(
params, node, part_name, part_type, part_value_expr, in_tablegroup))) {
LOG_WARN("resolve partition expr failed", K(ret));
} else if (OB_FAIL(part_value_expr_array.push_back(part_value_expr))) {
LOG_WARN("array push back fail", K(ret));
} else {
}
}
return ret;
}
// for recursively process columns item in resolve_partition_range_value_expr
// just wrap columns process logic in resolve_partition_range_value_expr
int ObResolverUtils::resolve_columns_for_partition_range_value_expr(ObRawExpr*& expr, ObArray<ObQualifiedName>& columns)
{
int ret = OB_SUCCESS;
ObArray<std::pair<ObRawExpr*, ObRawExpr*>> real_sys_exprs;
for (int64_t i = 0; OB_SUCC(ret) && i < columns.count(); i++) {
ObQualifiedName& q_name = columns.at(i);
if (q_name.is_sys_func()) {
ObSysFunRawExpr* sys_func_expr = q_name.access_idents_.at(0).sys_func_expr_;
if (OB_ISNULL(sys_func_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("sys expr is null", K(ret));
} else {
ObRawExpr* real_ref_expr = static_cast<ObRawExpr*>(sys_func_expr);
for (int64_t j = 0; OB_SUCC(ret) && j < real_sys_exprs.count(); ++j) {
if (OB_FAIL(ObRawExprUtils::replace_ref_column(
real_ref_expr, real_sys_exprs.at(j).first, real_sys_exprs.at(j).second))) {
LOG_WARN("failed to replace ref column", K(ret));
}
}
if (OB_FAIL(ret)) {
// do nothing
} else if (OB_FAIL(sys_func_expr->check_param_num())) {
LOG_WARN("faield to check param num", K(ret));
} else if (OB_FAIL(ObRawExprUtils::replace_ref_column(expr, q_name.ref_expr_, real_ref_expr))) {
LOG_WARN("failed to replace ref column", K(ret));
} else if (OB_FAIL(
real_sys_exprs.push_back(std::pair<ObRawExpr*, ObRawExpr*>(q_name.ref_expr_, real_ref_expr)))) {
LOG_WARN("failed to push back pari exprs", K(ret));
}
}
} else {
if (OB_FAIL(log_err_msg_for_partition_value(q_name))) {
LOG_WARN("log error msg for range value expr faield", K(ret));
}
}
}
return ret;
}
int ObResolverUtils::resolve_partition_range_value_expr(ObResolverParams& params, const ParseNode& node,
const ObString& part_name, const ObPartitionFuncType part_type, ObRawExpr*& part_value_expr,
const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
ObCollationType collation_connection = CS_TYPE_INVALID;
ObCharsetType character_set_connection = CHARSET_INVALID;
if (part_name.empty() && !lib::is_oracle_mode()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("part name is invalid", K(ret), K(part_name));
} else if (OB_ISNULL(params.expr_factory_) || OB_ISNULL(params.session_info_)) {
ret = OB_NOT_INIT;
LOG_WARN("resolve status is invalid", K_(params.expr_factory), K_(params.session_info));
} else if (OB_FAIL(params.session_info_->get_collation_connection(collation_connection))) {
LOG_WARN("fail to get collation_connection", K(ret));
} else if (OB_FAIL(params.session_info_->get_character_set_connection(character_set_connection))) {
LOG_WARN("fail to get character_set_connection", K(ret));
} else {
ObArray<ObQualifiedName> columns;
ObArray<ObSubQueryInfo> sub_query_info;
ObArray<ObVarInfo> sys_vars;
ObArray<ObAggFunRawExpr*> aggr_exprs;
ObArray<ObWinFunRawExpr*> win_exprs;
ObArray<ObColumnRefRawExpr*> part_column_refs;
ObArray<ObOpRawExpr*> op_exprs;
ObSEArray<ObUserVarIdentRawExpr*, 1> user_var_exprs;
ObExprResolveContext ctx(*params.expr_factory_, params.session_info_->get_timezone_info(), OB_NAME_CASE_INVALID);
ctx.dest_collation_ = collation_connection;
ctx.connection_charset_ = character_set_connection;
ctx.param_list_ = params.param_list_;
ctx.session_info_ = params.session_info_;
ctx.query_ctx_ = params.query_ctx_;
ObRawExprResolverImpl expr_resolver(ctx);
if (OB_FAIL(params.session_info_->get_name_case_mode(ctx.case_mode_))) {
LOG_WARN("fail to get name case mode", K(ret));
} else if (OB_FAIL(expr_resolver.resolve(&node,
part_value_expr,
columns,
sys_vars,
sub_query_info,
aggr_exprs,
win_exprs,
op_exprs,
user_var_exprs))) {
LOG_WARN("resolve expr failed", K(ret));
} else if (sub_query_info.count() > 0) {
ret = OB_ERR_PARTITION_FUNCTION_IS_NOT_ALLOWED;
} else if (OB_FAIL(resolve_columns_for_partition_range_value_expr(part_value_expr, columns))) {
LOG_WARN("resolve columns failed", K(ret));
}
if (OB_SUCC(ret)) {
if (OB_ISNULL(part_value_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("part expr should not be null", K(ret));
} else if (OB_FAIL(part_value_expr->formalize(params.session_info_))) {
LOG_WARN("formailize expr failed", K(ret));
} else if (OB_FAIL(check_partition_value_expr_for_range(part_name, *part_value_expr, part_type, in_tablegroup))) {
LOG_WARN("check_valid_column_for_hash or range func failed", K(part_type), K(part_name), K(ret));
}
}
}
return ret;
}
// for recursively process columns item in resolve_partition_expr
// just wrap columns process logic in resolve_partition_expr
int ObResolverUtils::resolve_columns_for_partition_expr(ObRawExpr*& expr, ObIArray<ObQualifiedName>& columns,
const ObTableSchema& tbl_schema, ObPartitionFuncType part_func_type, int64_t partition_key_start,
ObIArray<ObString>& partition_keys)
{
int ret = OB_SUCCESS;
ObArray<std::pair<ObRawExpr*, ObRawExpr*>> real_sys_exprs;
ObArray<ObColumnRefRawExpr*> part_column_refs;
for (int64_t i = 0; OB_SUCC(ret) && i < columns.count(); i++) {
const ObQualifiedName& q_name = columns.at(i);
ObRawExpr* real_ref_expr = NULL;
if (q_name.is_sys_func()) {
ObSysFunRawExpr* sys_func_expr = q_name.access_idents_.at(0).sys_func_expr_;
CK(OB_NOT_NULL(sys_func_expr));
if (OB_SUCC(ret)) {
real_ref_expr = static_cast<ObRawExpr*>(sys_func_expr);
for (int64_t i = 0; OB_SUCC(ret) && i < real_sys_exprs.count(); ++i) {
OZ(ObRawExprUtils::replace_ref_column(
real_ref_expr, real_sys_exprs.at(i).first, real_sys_exprs.at(i).second));
}
OZ(sys_func_expr->check_param_num());
OZ(ObRawExprUtils::replace_ref_column(expr, q_name.ref_expr_, real_ref_expr));
OZ(real_sys_exprs.push_back(std::pair<ObRawExpr*, ObRawExpr*>(q_name.ref_expr_, real_ref_expr)));
}
} else if (q_name.database_name_.length() > 0 || q_name.tbl_name_.length() > 0) {
ret = OB_ERR_BAD_FIELD_ERROR;
ObString scope_name = "partition function";
ObString col_name = concat_qualified_name(q_name.database_name_, q_name.tbl_name_, q_name.col_name_);
LOG_USER_ERROR(OB_ERR_BAD_FIELD_ERROR, col_name.length(), col_name.ptr(), scope_name.length(), scope_name.ptr());
} else if (OB_ISNULL(q_name.ref_expr_) || OB_UNLIKELY(!q_name.ref_expr_->is_column_ref_expr())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("ref expr is null", K_(q_name.ref_expr));
} else {
// check column name whether duplicated, if partition by key, duplicated column means error
// if partition by hash, add partition keys without duplicated name
const ObColumnSchemaV2* col_schema = NULL;
bool is_duplicated = false;
int64_t j = partition_key_start;
ObColumnRefRawExpr* col_expr = q_name.ref_expr_;
for (j = partition_key_start; OB_SUCC(ret) && j < partition_keys.count(); ++j) {
common::ObString& temp_name = partition_keys.at(j);
if (ObCharset::case_insensitive_equal(temp_name, q_name.col_name_)) {
is_duplicated = true;
break;
}
}
if (!is_duplicated) {
if (NULL == (col_schema = tbl_schema.get_column_schema(q_name.col_name_)) || col_schema->is_hidden()) {
ret = OB_ERR_BAD_FIELD_ERROR;
ObString scope_name = "partition function";
LOG_USER_ERROR(OB_ERR_BAD_FIELD_ERROR,
q_name.col_name_.length(),
q_name.col_name_.ptr(),
scope_name.length(),
scope_name.ptr());
} else if (col_schema->is_autoincrement()) {
ret = OB_ERR_AUTO_PARTITION_KEY;
LOG_USER_ERROR(OB_ERR_AUTO_PARTITION_KEY,
col_schema->get_column_name_str().length(),
col_schema->get_column_name_str().ptr());
} else if (OB_FAIL(partition_keys.push_back(q_name.col_name_))) {
LOG_WARN("add column name failed", K(ret), K_(q_name.col_name));
} else if (OB_FAIL(ObRawExprUtils::init_column_expr(*col_schema, *col_expr))) {
LOG_WARN("init column expr failed", K(ret));
} else if (OB_FAIL(part_column_refs.push_back(col_expr))) {
LOG_WARN("push back column expr failed", K(ret));
} else { /*do nothing*/
}
} else {
// for partition by key, duplicated column is forbidden
// for partition by hash, duplicated column must use the same column ref expr
ObColumnRefRawExpr* ref_expr = NULL;
if (PARTITION_FUNC_TYPE_KEY == part_func_type || PARTITION_FUNC_TYPE_KEY_V2 == part_func_type ||
PARTITION_FUNC_TYPE_KEY_V3 == part_func_type) {
ret = OB_ERR_SAME_NAME_PARTITION_FIELD;
LOG_USER_ERROR(OB_ERR_SAME_NAME_PARTITION_FIELD, q_name.col_name_.length(), q_name.col_name_.ptr());
} else if (OB_FAIL(part_column_refs.at(j - partition_key_start, ref_expr))) {
LOG_WARN(
"Failed to get part expr", K(ret), "idx", j - partition_key_start, "count", part_column_refs.count());
} else if (OB_ISNULL(ref_expr) || OB_ISNULL(col_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Part expr should not be NULL", K(ret), KPC(ref_expr), KPC(col_expr));
} else if (OB_FAIL(ObRawExprUtils::replace_ref_column(expr, col_expr, ref_expr))) {
LOG_WARN("replace column ref failed", K(ret));
} else { /*do nothing*/
}
}
}
}
return ret;
}
int ObResolverUtils::resolve_partition_expr(ObResolverParams& params, const ParseNode& node,
const ObTableSchema& tbl_schema, ObPartitionFuncType part_func_type, ObRawExpr*& part_expr,
ObIArray<ObString>* part_keys)
{
int ret = OB_SUCCESS;
ObArray<ObQualifiedName> columns;
ObArray<ObSubQueryInfo> sub_query_info;
ObArray<ObVarInfo> sys_vars;
ObArray<ObAggFunRawExpr*> aggr_exprs;
ObArray<ObWinFunRawExpr*> win_exprs;
ObArray<ObString> tmp_part_keys;
ObArray<ObOpRawExpr*> op_exprs;
ObSEArray<ObUserVarIdentRawExpr*, 1> user_var_exprs;
ObCollationType collation_connection = CS_TYPE_INVALID;
ObCharsetType character_set_connection = CHARSET_INVALID;
// part_keys is not null, means that need output partition keys
ObIArray<ObString>& partition_keys = (part_keys != NULL ? *part_keys : tmp_part_keys);
int64_t partition_key_start = partition_keys.count();
if (OB_ISNULL(params.expr_factory_) || OB_ISNULL(params.session_info_)) {
ret = OB_NOT_INIT;
LOG_WARN("resolve status is invalid", K_(params.expr_factory), K_(params.session_info));
} else if (OB_FAIL(params.session_info_->get_collation_connection(collation_connection))) {
LOG_WARN("fail to get collation_connection", K(ret));
} else if (OB_FAIL(params.session_info_->get_character_set_connection(character_set_connection))) {
LOG_WARN("fail to get character_set_connection", K(ret));
} else {
ObExprResolveContext ctx(*params.expr_factory_, params.session_info_->get_timezone_info(), OB_NAME_CASE_INVALID);
ctx.dest_collation_ = collation_connection;
ctx.connection_charset_ = character_set_connection;
ctx.param_list_ = params.param_list_;
ctx.session_info_ = params.session_info_;
ctx.query_ctx_ = params.query_ctx_;
ObRawExprResolverImpl expr_resolver(ctx);
if (OB_FAIL(params.session_info_->get_name_case_mode(ctx.case_mode_))) {
LOG_WARN("fail to get name case mode", K(ret));
} else if (OB_FAIL(expr_resolver.resolve(&node,
part_expr,
columns,
sys_vars,
sub_query_info,
aggr_exprs,
win_exprs,
op_exprs,
user_var_exprs))) {
LOG_WARN("resolve expr failed", K(ret));
} else if (sub_query_info.count() > 0) {
ret = OB_ERR_PARTITION_FUNCTION_IS_NOT_ALLOWED;
} else if (columns.size() <= 0) {
// partition by hash(1+1+1) /partition by range (1+1+1)
// handling cases like partition by hash(1)
ret = OB_ERR_WRONG_EXPR_IN_PARTITION_FUNC_ERROR;
LOG_WARN("const expr is invalid for thie type of partitioning", K(ret));
} else if (OB_FAIL(resolve_columns_for_partition_expr(
part_expr, columns, tbl_schema, part_func_type, partition_key_start, partition_keys))) {
LOG_WARN("resolve columns for partition expr failed", K(ret));
}
if (OB_SUCC(ret)) {
if (OB_ISNULL(part_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("part expr should not be null", K(ret));
} else if (share::is_oracle_mode() && is_hash_part(part_func_type)) {
if (OB_FAIL(check_partition_expr_for_oracle_hash(*part_expr, part_func_type))) {
LOG_WARN("check_partition_expr_for_oracle_hash func failed", K(ret));
}
} else if (is_hash_part(part_func_type) || is_range_part(part_func_type) || is_list_part(part_func_type)) {
if (OB_FAIL(check_partition_expr_for_hash_or_range(*part_expr, part_func_type))) {
LOG_WARN("check_valid_column_for_hash or range func failed", K(ret));
}
}
}
if (OB_SUCC(ret) && OB_FAIL(part_expr->formalize(params.session_info_))) {
LOG_WARN("formailize expr failed", K(ret));
}
}
return ret;
}
int ObResolverUtils::resolve_generated_column_expr(ObResolverParams& params, const ObString& expr_str,
ObTableSchema& tbl_schema, ObColumnSchemaV2& generated_column, ObRawExpr*& expr)
{
int ret = OB_SUCCESS;
const ParseNode* expr_node = NULL;
if (OB_ISNULL(params.allocator_)) {
ret = OB_INVALID_ARGUMENT;
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))) {
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)
{
int ret = OB_SUCCESS;
ObColumnSchemaV2* col_schema = NULL;
ObSEArray<ObQualifiedName, 2> columns;
ObSEArray<std::pair<ObRawExpr*, ObRawExpr*>, 2> ref_sys_exprs;
ObSQLSessionInfo* session_info = params.session_info_;
ObRawExprFactory* expr_factory = params.expr_factory_;
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))) {
LOG_WARN("build generated column expr failed", K(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && i < columns.count(); ++i) {
const ObQualifiedName& q_name = columns.at(i);
if (q_name.is_sys_func()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("generated column expr has invalid qualified name", K(q_name));
} else if (q_name.database_name_.length() > 0 || q_name.tbl_name_.length() > 0) {
ret = OB_ERR_BAD_FIELD_ERROR;
ObString scope_name = "generated column function";
ObString col_name = concat_qualified_name(q_name.database_name_, q_name.tbl_name_, q_name.col_name_);
LOG_USER_ERROR(OB_ERR_BAD_FIELD_ERROR, col_name.length(), col_name.ptr(), scope_name.length(), scope_name.ptr());
} else if (NULL == (col_schema = tbl_schema.get_column_schema(q_name.col_name_)) || col_schema->is_hidden()) {
ret = OB_ERR_BAD_FIELD_ERROR;
ObString scope_name = "generated column function";
LOG_USER_ERROR(OB_ERR_BAD_FIELD_ERROR,
q_name.col_name_.length(),
q_name.col_name_.ptr(),
scope_name.length(),
scope_name.ptr());
} else if (col_schema->is_generated_column()) {
ret = OB_ERR_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN;
LOG_USER_ERROR(
OB_ERR_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN, "Defining a generated column on generated column(s)");
} else if (share::is_oracle_mode() && col_schema->get_meta_type().is_blob()) {
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 (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()))) {
LOG_WARN("add cascaded column id to generated column failed", K(ret));
} else {
col_schema->add_column_flag(GENERATED_DEPS_CASCADE_FLAG);
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(expr->formalize(session_info))) {
LOG_WARN("formalize expr failed", K(ret));
} else if (share::is_oracle_mode() && ob_is_string_type(generated_column.get_data_type())) {
int64_t generated_column_length_in_byte = 0;
int64_t expr_length_in_byte = 0;
common::ObCollationType cs_type = generated_column.get_collation_type();
int64_t mbmaxlen = 1;
if (LS_CHAR == generated_column.get_length_semantics()) {
if (OB_FAIL(common::ObCharset::get_mbmaxlen_by_coll(cs_type, mbmaxlen))) {
LOG_WARN("fail to get mbmaxlen for generated_column", K(cs_type), K(ret));
} else {
generated_column_length_in_byte = generated_column.get_data_length() * mbmaxlen;
}
} else {
generated_column_length_in_byte = generated_column.get_data_length();
}
if (OB_SUCC(ret)) {
if (LS_CHAR == expr->get_accuracy().get_length_semantics()) {
cs_type = expr->get_collation_type();
if (OB_FAIL(common::ObCharset::get_mbmaxlen_by_coll(cs_type, mbmaxlen))) {
LOG_WARN("fail to get mbmaxlen for expr", K(cs_type), K(ret));
} else {
expr_length_in_byte = expr->get_accuracy().get_length() * mbmaxlen;
}
} else {
expr_length_in_byte = expr->get_accuracy().get_length();
}
}
if (OB_SUCC(ret) && OB_UNLIKELY(generated_column_length_in_byte < expr_length_in_byte)) {
ret = OB_ERR_DATA_TOO_LONG;
LOG_WARN("the length of generated column expr is more than the length of specified type",
K(generated_column_length_in_byte),
K(expr_length_in_byte));
}
} else if (ob_is_raw(generated_column.get_data_type())) {
if (ob_is_string_type(expr->get_data_type())) {
if (OB_UNLIKELY(generated_column.get_data_length() * 2 < (expr->get_accuracy()).get_length())) {
ret = OB_ERR_DATA_TOO_LONG;
LOG_WARN("the length of generated column expr is more than the length of specified type");
}
} else if (ob_is_raw(expr->get_data_type())) {
if (OB_UNLIKELY(generated_column.get_data_length() < (expr->get_accuracy()).get_length())) {
ret = OB_ERR_DATA_TOO_LONG;
LOG_WARN("the length of generated column expr is more than the length of specified type");
}
} else {
ret = OB_ERR_INVALID_TYPE_FOR_OP;
LOG_WARN("inconsistent datatypes", K(expr->get_result_type().get_type()));
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(ObDDLResolver::print_expr_to_default_value(
*expr, generated_column, session_info->get_timezone_info()))) {
LOG_WARN("fail to print_expr_to_default_value", KPC(expr), K(generated_column), 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)
{
int ret = OB_SUCCESS;
const ParseNode* expr_node = NULL;
if (OB_ISNULL(params.allocator_)) {
ret = OB_INVALID_ARGUMENT;
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_default_expr_v2_column_expr(params, expr_node, default_expr_v2_column, expr))) {
LOG_WARN("resolve default_expr_v2_column expr failed", K(ret), K(expr_str));
}
return ret;
}
int ObResolverUtils::resolve_default_expr_v2_column_expr(
ObResolverParams& params, const ParseNode* node, ObColumnSchemaV2& default_expr_v2_column, ObRawExpr*& expr)
{
int ret = OB_SUCCESS;
ObArray<ObQualifiedName> columns;
ObSQLSessionInfo* session_info = params.session_info_;
ObRawExprFactory* expr_factory = params.expr_factory_;
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))) {
LOG_WARN("build expr_default column expr failed",
"is_oracle_compatible",
session_info->get_compatibility_mode(),
K(ret));
} else if (share::is_oracle_mode() && columns.count() > 0) {
bool is_all_sys_func = true;
ObRawExpr* real_ref_expr = NULL;
for (int64_t i = 0; OB_SUCC(ret) && is_all_sys_func && i < columns.count(); i++) {
ObQualifiedName& q_name = columns.at(i);
if (!q_name.is_sys_func()) {
is_all_sys_func = false;
} else if (OB_ISNULL(q_name.access_idents_.at(0).sys_func_expr_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret));
} else if (OB_FAIL(q_name.access_idents_.at(0).sys_func_expr_->check_param_num())) {
LOG_WARN("sys func param number not match", K(ret));
} else {
real_ref_expr = static_cast<ObRawExpr*>(q_name.access_idents_.at(0).sys_func_expr_);
if (OB_FAIL(ObRawExprUtils::replace_ref_column(expr, q_name.ref_expr_, real_ref_expr))) {
LOG_WARN("replace column ref expr failed", K(ret));
} else {
real_ref_expr = NULL;
}
}
}
if (!is_all_sys_func) {
// log user error
ret = OB_ERR_BAD_FIELD_ERROR;
const ObQualifiedName& q_name = columns.at(0);
ObString scope_name = default_expr_v2_column.get_column_name_str();
ObString col_name = concat_qualified_name(q_name.database_name_, q_name.tbl_name_, q_name.col_name_);
LOG_USER_ERROR(OB_ERR_BAD_FIELD_ERROR, col_name.length(), col_name.ptr(), scope_name.length(), scope_name.ptr());
}
if (OB_FAIL(ret)) {
// do nothing
} else if (OB_FAIL(expr->formalize(session_info))) {
LOG_WARN("formalize expr failed", K(ret));
} else {
LOG_DEBUG("succ to resolve_default_expr_v2_column_expr",
"is_const_expr",
expr->is_const_expr(),
"is_calculable_expr",
expr->has_flag(IS_CALCULABLE_EXPR),
KPC(expr),
K(ret));
}
} else if (OB_UNLIKELY(!columns.empty())) {
ret = OB_ERR_BAD_FIELD_ERROR;
const ObQualifiedName& q_name = columns.at(0);
ObString scope_name = default_expr_v2_column.get_column_name_str();
ObString col_name = concat_qualified_name(q_name.database_name_, q_name.tbl_name_, q_name.col_name_);
LOG_USER_ERROR(OB_ERR_BAD_FIELD_ERROR, col_name.length(), col_name.ptr(), scope_name.length(), scope_name.ptr());
} else if (OB_FAIL(expr->formalize(session_info))) {
LOG_WARN("formalize expr failed", K(ret));
} else {
LOG_DEBUG("succ to resolve_default_expr_v2_column_expr",
"is_const_expr",
expr->is_const_expr(),
"is_calculable_expr",
expr->has_flag(IS_CALCULABLE_EXPR),
KPC(expr),
K(ret));
}
return ret;
}
int ObResolverUtils::resolve_check_constraint_expr(ObResolverParams& params, const ParseNode* node,
const ObTableSchema& tbl_schema, ObConstraint& constraint, ObRawExpr*& expr,
const share::schema::ObColumnSchemaV2* column_schema)
{
int ret = OB_SUCCESS;
ObArray<ObQualifiedName> columns;
ObArray<std::pair<ObRawExpr*, ObRawExpr*>> ref_sys_exprs;
ObSQLSessionInfo* session_info = params.session_info_;
ObRawExprFactory* expr_factory = params.expr_factory_;
bool is_col_level_cst = false; // table level cst
common::ObSEArray<uint64_t, common::SEARRAY_INIT_NUM> column_ids;
if (NULL != column_schema) {
// column_schema is NULL, table level constraint
is_col_level_cst = true;
}
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_check_constraint_expr(*expr_factory, *session_info, *node, expr, columns))) {
LOG_WARN("build generated column expr failed", K(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && i < columns.count(); ++i) {
const ObQualifiedName& q_name = columns.at(i);
if (q_name.is_sys_func()) {
ObRawExpr* sys_func = q_name.access_idents_.at(0).sys_func_expr_;
CK(OB_NOT_NULL(sys_func));
if (OB_SUCC(ret) &&
(T_FUN_SYS_SYS_CONTEXT == sys_func->get_expr_type() || T_FUN_SYS_USERENV == sys_func->get_expr_type())) {
ret = OB_ERR_DATE_OR_SYS_VAR_CANNOT_IN_CHECK_CST;
LOG_WARN("date or system variable wrongly specified in CHECK constraint", K(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && i < ref_sys_exprs.count(); ++i) {
OZ(ObRawExprUtils::replace_ref_column(sys_func, ref_sys_exprs.at(i).first, ref_sys_exprs.at(i).second));
}
OZ(q_name.access_idents_.at(0).sys_func_expr_->check_param_num());
OZ(ObRawExprUtils::replace_ref_column(expr, q_name.ref_expr_, sys_func));
OZ(ref_sys_exprs.push_back(std::pair<ObRawExpr*, ObRawExpr*>(q_name.ref_expr_, sys_func)));
} else if (q_name.database_name_.length() > 0 || q_name.tbl_name_.length() > 0) {
ret = OB_ERR_BAD_FIELD_ERROR;
ObString scope_name = "constraint column function";
ObString col_name = concat_qualified_name(q_name.database_name_, q_name.tbl_name_, q_name.col_name_);
LOG_USER_ERROR(OB_ERR_BAD_FIELD_ERROR, col_name.length(), col_name.ptr(), scope_name.length(), scope_name.ptr());
} else {
if (!is_col_level_cst) {
if (OB_ISNULL(column_schema = tbl_schema.get_column_schema(q_name.col_name_)) || column_schema->is_hidden()) {
ret = OB_ERR_BAD_FIELD_ERROR;
ObString scope_name = "constraint column function";
LOG_USER_ERROR(OB_ERR_BAD_FIELD_ERROR,
q_name.col_name_.length(),
q_name.col_name_.ptr(),
scope_name.length(),
scope_name.ptr());
}
} else { // is_col_level_cst
if (0 != columns.at(i).col_name_.compare(column_schema->get_column_name_str())) {
ret = OB_ERR_COL_CHECK_CST_REFER_ANOTHER_COL;
LOG_WARN("column check constraint cannot reference other columns",
K(ret),
K(columns.at(i).col_name_),
K(column_schema->get_column_name_str()));
}
}
if (OB_SUCC(ret)) {
if (column_ids.end() == std::find(column_ids.begin(), column_ids.end(), column_schema->get_column_id())) {
if (OB_FAIL(column_ids.push_back(column_schema->get_column_id()))) {
LOG_WARN("push back to column_ids failed", K(ret), K(column_schema->get_column_id()));
}
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(ObRawExprUtils::init_column_expr(*column_schema, *q_name.ref_expr_))) {
LOG_WARN("init column expr failed", K(ret));
}
}
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(constraint.assign_column_ids(column_ids))) {
LOG_WARN("fail to assign_column_ids", K(column_ids));
}
}
if (OB_SUCC(ret) && OB_FAIL(expr->formalize(session_info))) {
LOG_WARN("formalize expr failed", K(ret));
}
if (OB_SUCC(ret) && share::is_mysql_mode()) {
if (T_OP_EQ != expr->get_expr_type()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("constraint expr type should be T_OP_EQ", K(expr->get_expr_type()), K(ret));
} else {
ObOpRawExpr* eq_expr = static_cast<ObOpRawExpr*>(expr);
ObRawExpr* exprs[2] = {eq_expr->get_param_expr(0), eq_expr->get_param_expr(1)};
for (int i = 0; OB_SUCC(ret) && i < 2; i++) {
if (OB_ISNULL(exprs[i])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(exprs[i]));
} else if (T_FUN_SYS_SUBSTR == exprs[i]->get_expr_type()) {
ObSysFunRawExpr* sys_expr = static_cast<ObSysFunRawExpr*>(exprs[i]);
for (int64_t j = 0; OB_SUCC(ret) && j < sys_expr->get_param_count(); j++) {
ObRawExpr* param_expr = sys_expr->get_param_expr(j);
if (OB_ISNULL(param_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret), K(param_expr));
} else if (0 == j && !param_expr->is_column_ref_expr()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("column ref expr expected", K(ret), K(param_expr->get_expr_type()));
} else if (0 != j && !param_expr->is_const_expr()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("const expr expected", K(ret), K(param_expr->get_expr_type()));
}
}
} else if (exprs[i]->is_column_ref_expr()) {
// do-nothing
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("substring or column ref expr expected", K(ret), K(exprs[i]->get_expr_type()));
}
}
}
}
if (OB_SUCC(ret)) {
HEAP_VAR(char[OB_MAX_DEFAULT_VALUE_LENGTH], expr_str_buf)
{
MEMSET(expr_str_buf, 0, sizeof(expr_str_buf));
int64_t pos = 0;
ObString expr_def;
ObRawExprPrinter expr_printer(expr_str_buf, OB_MAX_DEFAULT_VALUE_LENGTH, &pos, session_info->get_timezone_info());
if (OB_FAIL(expr_printer.do_print(expr, T_NONE_SCOPE, true))) {
LOG_WARN("print expr definition failed", K(ret));
} else if (FALSE_IT(expr_def.assign_ptr(expr_str_buf, static_cast<int32_t>(pos)))) {
} else if (OB_FAIL(constraint.set_check_expr(expr_def))) {
LOG_WARN("set check expr failed", K(ret));
}
}
}
return ret;
}
int ObResolverUtils::build_partition_key_expr(ObResolverParams& params,
const share::schema::ObTableSchema& table_schema, ObRawExpr*& partition_key_expr,
ObIArray<ObQualifiedName>* qualified_names, const bool is_key_implicit_v2)
{
int ret = OB_SUCCESS;
ObSysFunRawExpr* func_expr = NULL;
if (OB_ISNULL(params.expr_factory_)) {
ret = OB_NOT_INIT;
LOG_WARN("expr factory is null", K(params.expr_factory_));
} else if (!is_key_implicit_v2 && OB_FAIL(params.expr_factory_->create_raw_expr(T_FUN_SYS_PART_KEY_V2, func_expr))) {
LOG_WARN("create sysfunc expr failed", K(ret));
} else if (is_key_implicit_v2 && OB_FAIL(params.expr_factory_->create_raw_expr(T_FUN_SYS_PART_KEY_V3, func_expr))) {
LOG_WARN("create sysfunc expr failed", K(ret));
} else {
if (is_key_implicit_v2) {
ObString partition_fun_name("partition_key_v3");
func_expr->set_func_name(partition_fun_name);
} else {
ObString partition_fun_name("partition_key_v2");
func_expr->set_func_name(partition_fun_name);
}
if (OB_FAIL(func_expr->add_flag(IS_FUNC))) {
LOG_WARN("failed to add flag IS_FUNC");
} else if (OB_FAIL(func_expr->add_flag(CNT_COLUMN))) {
LOG_WARN("failed to add flag CNT_COLUMN");
} else if (OB_FAIL(func_expr->add_flag(CNT_FUNC))) {
LOG_WARN("failed to add flag CNT_FUNC");
} else {
}
}
// use primary key column to build a ObColumnRefRawExpr
for (ObTableSchema::const_column_iterator iter = table_schema.column_begin();
OB_SUCC(ret) && iter != table_schema.column_end();
++iter) {
const ObColumnSchemaV2& column_schema = (**iter);
if (!column_schema.is_original_rowkey_column() || column_schema.is_hidden()) {
// parition by key() use primary key to create partition key not hidden auto_increment primary key
continue;
} else if (column_schema.is_autoincrement()) {
ret = OB_ERR_AUTO_PARTITION_KEY;
LOG_USER_ERROR(OB_ERR_AUTO_PARTITION_KEY,
column_schema.get_column_name_str().length(),
column_schema.get_column_name_str().ptr());
} else {
ObColumnRefRawExpr* column_expr = NULL;
if (OB_FAIL(ObRawExprUtils::build_column_expr(*params.expr_factory_, column_schema, column_expr))) {
LOG_WARN("failed to build column schema!", K(column_expr), K(column_schema));
} else if (OB_FAIL(func_expr->add_param_expr(column_expr))) {
LOG_WARN("failed to add param expr!", K(ret));
} else if (qualified_names != NULL) {
ObQualifiedName name;
name.col_name_.assign_ptr(column_schema.get_column_name(), column_schema.get_column_name_str().length());
name.ref_expr_ = column_expr;
name.is_star_ = false;
if (OB_FAIL(qualified_names->push_back(name))) {
LOG_WARN("failed to push back qualified name", K(ret));
}
}
}
}
if (OB_SUCC(ret)) {
partition_key_expr = func_expr;
if (OB_FAIL(partition_key_expr->formalize(params.session_info_))) {
LOG_WARN("deduce type failed", K(ret));
}
}
return ret;
}
int ObResolverUtils::check_column_name(const ObSQLSessionInfo* session_info, const ObQualifiedName& q_name,
const ObColumnRefRawExpr& col_ref, bool& is_hit)
{
int ret = OB_SUCCESS;
is_hit = true;
if (!q_name.database_name_.empty()) {
if (OB_FAIL(name_case_cmp(
session_info, q_name.database_name_, col_ref.get_database_name(), OB_TABLE_NAME_CLASS, is_hit))) {
LOG_WARN("cmp database name failed", K(ret), K(q_name), K(col_ref.get_database_name()));
}
}
if (OB_SUCC(ret) && !q_name.tbl_name_.empty() && is_hit) {
ObString table_name = col_ref.get_synonym_name().empty() ? col_ref.get_table_name() : col_ref.get_synonym_name();
if (OB_FAIL(name_case_cmp(session_info, q_name.tbl_name_, table_name, OB_TABLE_NAME_CLASS, is_hit))) {
LOG_WARN("compare table name failed", K(q_name), K(q_name), K(col_ref));
}
}
if (OB_SUCC(ret) && is_hit) {
is_hit = ObCharset::case_insensitive_equal(q_name.col_name_, col_ref.get_column_name());
}
return ret;
}
int ObResolverUtils::create_generate_table_column(
ObRawExprFactory& expr_factory, const TableItem& table_item, uint64_t column_id, ColumnItem& col_item)
{
int ret = OB_SUCCESS;
ObColumnRefRawExpr* col_expr = NULL;
if (OB_UNLIKELY(!table_item.is_generated_table())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("not generated table", K_(table_item.type));
} else {
int64_t item_index = column_id - OB_APP_MIN_COLUMN_ID;
ObSelectStmt* ref_stmt = table_item.ref_query_;
if (OB_ISNULL(ref_stmt)) {
ret = OB_NOT_INIT;
LOG_WARN("generate table ref stmt is null");
} else if (OB_UNLIKELY(item_index < 0 || item_index >= ref_stmt->get_select_item_size())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("select item index is invalid", K(item_index), K(ref_stmt->get_select_item_size()));
} else if (OB_FAIL(expr_factory.create_raw_expr(T_REF_COLUMN, col_expr))) {
LOG_WARN("create column ref expr failed", K(ret));
} else if (OB_ISNULL(col_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("col expr is null");
} else {
col_expr->set_ref_id(table_item.table_id_, column_id);
col_expr->set_result_type(ref_stmt->get_select_item(item_index).expr_->get_result_type());
col_expr->set_column_attr(table_item.alias_name_, ref_stmt->get_select_item(item_index).alias_name_);
col_item.set_default_value(ref_stmt->get_select_item(item_index).default_value_);
}
}
// init column item
if (OB_SUCC(ret)) {
col_item.expr_ = col_expr;
col_item.table_id_ = col_expr->get_table_id();
col_item.column_id_ = col_expr->get_column_id();
col_item.column_name_ = col_expr->get_column_name();
}
return ret;
}
int ObResolverUtils::check_unique_index_cover_partition_column(
const ObTableSchema& table_schema, const ObCreateIndexArg& arg)
{
int ret = OB_SUCCESS;
if (!table_schema.is_partitioned_table() ||
(INDEX_TYPE_PRIMARY != arg.index_type_ && INDEX_TYPE_UNIQUE_LOCAL != arg.index_type_ &&
INDEX_TYPE_UNIQUE_GLOBAL != arg.index_type_)) {
// nothing to do
} else {
const common::ObPartitionKeyInfo& partition_info = table_schema.get_partition_key_info();
const common::ObPartitionKeyInfo& subpartition_info = table_schema.get_subpartition_key_info();
ObSEArray<uint64_t, 5> idx_col_ids;
if (OB_FAIL(get_index_column_ids(table_schema, arg.index_columns_, idx_col_ids))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Failed to get index column ids", K(ret), K(table_schema), K(arg.index_columns_));
} else if (OB_FAIL(unique_idx_covered_partition_columns(table_schema, idx_col_ids, partition_info))) {
LOG_WARN("Unique index covered partition columns failed", K(ret));
} else if (OB_FAIL(unique_idx_covered_partition_columns(table_schema, idx_col_ids, subpartition_info))) {
LOG_WARN("Unique index convered partition columns failed", K(ret));
} else {
} // do nothing
}
return ret;
}
int ObResolverUtils::get_index_column_ids(
const ObTableSchema& table_schema, const ObIArray<ObColumnSortItem>& columns, ObIArray<uint64_t>& column_ids)
{
int ret = OB_SUCCESS;
const ObColumnSchemaV2* column_schema = NULL;
for (int64_t idx = 0; OB_SUCC(ret) && idx < columns.count(); ++idx) {
if (OB_ISNULL(column_schema = table_schema.get_column_schema(columns.at(idx).column_name_))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Failed to get column schema", K(ret), "column id", columns.at(idx));
} else if (OB_FAIL(column_ids.push_back(column_schema->get_column_id()))) {
LOG_WARN("Failed to add column id", K(ret));
} else {
} // do nothing
}
return ret;
}
int ObResolverUtils::unique_idx_covered_partition_columns(const ObTableSchema& table_schema,
const ObIArray<uint64_t>& index_columns, const ObPartitionKeyInfo& partition_info)
{
int ret = OB_SUCCESS;
const ObColumnSchemaV2* column_schema = NULL;
const ObPartitionKeyColumn* column = NULL;
for (int64_t i = 0; OB_SUCC(ret) && i < partition_info.get_size(); i++) {
column = partition_info.get_column(i);
if (OB_ISNULL(column)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("fail to get parition info", K(ret), K(column));
} else if (!has_exist_in_array(index_columns, column->column_id_)) {
if (OB_ISNULL(column_schema = table_schema.get_column_schema(column->column_id_))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Column schema is NULL", K(ret));
} else if (column_schema->is_generated_column()) {
ObSEArray<uint64_t, 5> cascaded_columns;
if (OB_FAIL(column_schema->get_cascaded_column_ids(cascaded_columns))) {
LOG_WARN("Failed to get cascaded column ids", K(ret));
} else {
for (int64_t idx = 0; OB_SUCC(ret) && idx < cascaded_columns.count(); ++idx) {
if (!has_exist_in_array(index_columns, cascaded_columns.at(idx))) {
ret = OB_EER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF;
LOG_USER_ERROR(OB_EER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF, "UNIQUE INDEX");
}
}
}
} else {
ret = OB_EER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF;
LOG_USER_ERROR(OB_EER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF, "UNIQUE INDEX");
}
} else {
} // do nothing
} // end for
return ret;
}
int ObResolverUtils::resolve_data_type(const ParseNode& type_node, const ObString& ident_name, ObDataType& data_type,
const int is_oracle_mode /*1:Oracle, 0:MySql */, const ObSessionNLSParams& nls_session_param)
{
int ret = OB_SUCCESS;
data_type.set_obj_type(static_cast<ObObjType>(type_node.type_));
int32_t length = type_node.int32_values_[0];
int16_t precision = type_node.int16_values_[0];
int16_t scale = type_node.int16_values_[1];
const int16_t number_type = type_node.int16_values_[2];
int64_t max_precision = PRECISION_UNKNOWN_YET;
int64_t max_scale = SCALE_UNKNOWN_YET;
const ObAccuracy& default_accuracy = ObAccuracy::DDL_DEFAULT_ACCURACY2[is_oracle_mode][data_type.get_obj_type()];
const bool has_specify_scale = (1 == type_node.int16_values_[2]);
LOG_DEBUG("resolve_data_type",
K(ret),
K(has_specify_scale),
K(type_node.type_),
K(type_node.param_num_),
K(number_type),
K(scale),
K(precision),
K(length));
switch (data_type.get_type_class()) {
case ObIntTC:
// fallthrough
case ObUIntTC:
if (precision <= 0) {
precision = default_accuracy.get_precision();
}
if (precision > OB_MAX_INTEGER_DISPLAY_WIDTH) {
ret = OB_ERR_TOO_BIG_DISPLAYWIDTH;
LOG_USER_ERROR(OB_ERR_TOO_BIG_DISPLAYWIDTH, ident_name.ptr(), OB_MAX_INTEGER_DISPLAY_WIDTH);
} else {
data_type.set_precision(precision);
data_type.set_scale(0);
}
data_type.set_zero_fill(static_cast<bool>(type_node.int16_values_[2]));
break;
case ObFloatTC:
// fallthrough
case ObDoubleTC: {
if (is_oracle_mode) {
data_type.set_precision(precision);
data_type.set_scale(scale);
} else {
if (OB_UNLIKELY(scale > OB_MAX_DOUBLE_FLOAT_SCALE)) {
ret = OB_ERR_TOO_BIG_SCALE;
LOG_USER_ERROR(OB_ERR_TOO_BIG_SCALE, scale, ident_name.ptr(), OB_MAX_DOUBLE_FLOAT_SCALE);
LOG_WARN("scale of double overflow", K(ret), K(scale), K(precision));
} else if (OB_UNLIKELY(precision > OB_MAX_DOUBLE_FLOAT_PRECISION)) {
ret = OB_ERR_COLUMN_SPEC;
LOG_USER_ERROR(OB_ERR_COLUMN_SPEC, ident_name.length(), ident_name.ptr());
LOG_WARN("precision of double overflow", K(ret), K(scale), K(precision));
} else if (OB_UNLIKELY(precision < scale)) {
ret = OB_ERR_M_BIGGER_THAN_D;
LOG_USER_ERROR(OB_ERR_M_BIGGER_THAN_D, to_cstring(ident_name));
LOG_WARN("precision less then scale", K(ret), K(scale), K(precision));
} else {
// mysql> create table t1(a decimal(0, 0));
// mysql> desc t1;
// +-------+---------------+------+-----+---------+-------+
// | Field | Type | Null | Key | Default | Extra |
// +-------+---------------+------+-----+---------+-------+
// | a | decimal(10,0) | YES | | NULL | |
// +-------+---------------+------+-----+---------+-------+
// the same as float and double.
if (precision <= 0 && scale <= 0) {
precision = default_accuracy.get_precision();
scale = default_accuracy.get_scale();
}
// A precision from 24 to 53 results in an 8-byte double-precision DOUBLE column.
if (T_FLOAT == type_node.type_ && precision > OB_MAX_FLOAT_PRECISION && -1 == scale) {
data_type.set_obj_type(static_cast<ObObjType>(T_DOUBLE));
}
data_type.set_precision(precision);
data_type.set_scale(scale);
data_type.set_zero_fill(static_cast<bool>(type_node.int16_values_[2]));
}
}
break;
}
case ObNumberTC: {
if (data_type.get_meta_type().is_number_float()) {
if (precision != PRECISION_UNKNOWN_YET && (OB_UNLIKELY(precision < OB_MIN_NUMBER_FLOAT_PRECISION) ||
OB_UNLIKELY(precision > OB_MAX_NUMBER_FLOAT_PRECISION))) {
ret = OB_FLOAT_PRECISION_OUT_RANGE;
LOG_WARN("precision of float out of range", K(ret), K(precision));
} else {
data_type.set_precision(precision);
data_type.set_scale(ORA_NUMBER_SCALE_UNKNOWN_YET);
}
} else if (is_oracle_mode) {
if ((number_type == NPT_PERC_SCALE || number_type == NPT_PERC) &&
(OB_UNLIKELY(precision < OB_MIN_NUMBER_PRECISION) || OB_UNLIKELY(precision > OB_MAX_NUMBER_PRECISION))) {
ret = OB_NUMERIC_PRECISION_OUT_RANGE;
LOG_WARN("precision of number overflow", K(ret), K(scale), K(precision));
}
if (OB_SUCC(ret)) {
if ((number_type == NPT_PERC_SCALE || number_type == NPT_STAR_SCALE) &&
(OB_UNLIKELY(scale < OB_MIN_NUMBER_SCALE) || OB_UNLIKELY(scale > OB_MAX_NUMBER_SCALE))) {
ret = OB_NUMERIC_SCALE_OUT_RANGE;
LOG_WARN("scale of number out of range", K(ret), K(scale));
}
}
if (OB_SUCC(ret)) {
data_type.set_precision(precision);
data_type.set_scale(scale);
}
} else {
if (OB_UNLIKELY(precision > OB_MAX_DECIMAL_PRECISION)) {
ret = OB_ERR_TOO_BIG_PRECISION;
LOG_USER_ERROR(OB_ERR_TOO_BIG_PRECISION, precision, ident_name.ptr(), OB_MAX_DECIMAL_PRECISION);
LOG_WARN("precision of number overflow", K(ret), K(scale), K(precision));
} else if (OB_UNLIKELY(scale > OB_MAX_DECIMAL_SCALE)) {
ret = OB_ERR_TOO_BIG_SCALE;
LOG_USER_ERROR(OB_ERR_TOO_BIG_SCALE, scale, ident_name.ptr(), OB_MAX_DECIMAL_SCALE);
LOG_WARN("scale of number overflow", K(ret), K(scale), K(precision));
} else if (OB_UNLIKELY(precision < scale)) {
ret = OB_ERR_M_BIGGER_THAN_D;
LOG_USER_ERROR(OB_ERR_M_BIGGER_THAN_D, to_cstring(ident_name));
LOG_WARN("precision less then scale", K(ret), K(scale), K(precision));
} else {
// mysql> create table t1(a decimal(0, 0));
// mysql> desc t1;
// +-------+---------------+------+-----+---------+-------+
// | Field | Type | Null | Key | Default | Extra |
// +-------+---------------+------+-----+---------+-------+
// | a | decimal(10,0) | YES | | NULL | |
// +-------+---------------+------+-----+---------+-------+
// the same as float and double.
if (precision <= 0 && scale <= 0) {
precision = default_accuracy.get_precision();
scale = default_accuracy.get_scale();
}
data_type.set_precision(precision);
data_type.set_scale(scale);
data_type.set_zero_fill(static_cast<bool>(type_node.int16_values_[2]));
}
}
break;
}
case ObOTimestampTC:
if (!has_specify_scale) {
scale = default_accuracy.get_scale();
}
if (OB_UNLIKELY(scale > OB_MAX_TIMESTAMP_TZ_PRECISION)) {
ret = OB_ERR_DATETIME_INTERVAL_PRECISION_OUT_OF_RANGE;
} else {
data_type.set_precision(static_cast<int16_t>(default_accuracy.get_precision() + scale));
data_type.set_scale(scale);
}
break;
case ObDateTimeTC:
if (scale > OB_MAX_DATETIME_PRECISION) {
ret = OB_ERR_TOO_BIG_PRECISION;
LOG_USER_ERROR(OB_ERR_TOO_BIG_PRECISION, scale, ident_name.ptr(), OB_MAX_DATETIME_PRECISION);
} else {
data_type.set_precision(static_cast<int16_t>(default_accuracy.get_precision() + scale));
data_type.set_scale(scale);
}
break;
case ObDateTC:
// nothing to do.
data_type.set_precision(default_accuracy.get_precision());
data_type.set_scale(default_accuracy.get_scale());
break;
case ObTimeTC:
if (scale > OB_MAX_DATETIME_PRECISION) {
ret = OB_ERR_TOO_BIG_PRECISION;
LOG_USER_ERROR(OB_ERR_TOO_BIG_PRECISION, scale, ident_name.ptr(), OB_MAX_DATETIME_PRECISION);
} else {
if (scale < 0) {
scale = default_accuracy.get_scale();
}
data_type.set_precision(static_cast<int16_t>(default_accuracy.get_precision() + scale));
data_type.set_scale(scale);
}
break;
case ObYearTC:
data_type.set_precision(default_accuracy.get_precision());
data_type.set_scale(default_accuracy.get_scale());
// nothing to do.
break;
case ObStringTC:
data_type.set_length(length);
if (ObVarcharType != data_type.get_obj_type() && ObCharType != data_type.get_obj_type() &&
ObNVarchar2Type != data_type.get_obj_type() && ObNCharType != data_type.get_obj_type()) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "column type must be ObVarcharType or ObCharType", K(ret));
} else if (type_node.int32_values_[1] /*is binary*/) {
data_type.set_charset_type(CHARSET_BINARY);
data_type.set_collation_type(CS_TYPE_BINARY);
} else if (OB_FAIL(resolve_str_charset_info(type_node, data_type))) {
SQL_RESV_LOG(WARN, "fail to resolve string charset and collation", K(ret), K(data_type));
} else if (is_oracle_mode) {
int64_t nchar_mbminlen = 0;
ObCollationType cs_type = ob_is_nstring_type(data_type.get_obj_type()) ? nls_session_param.nls_nation_collation_
: nls_session_param.nls_collation_;
if (OB_UNLIKELY(0 == length)) {
ret = OB_ERR_ZERO_LEN_COL;
LOG_WARN("Oracle not allowed zero length", K(ret));
} else if (OB_FAIL(ObCharset::get_mbminlen_by_coll(nls_session_param.nls_nation_collation_, nchar_mbminlen))) {
LOG_WARN("fail to get mbminlen of nchar", K(ret), K(nls_session_param));
} else if (((ObVarcharType == data_type.get_obj_type() || ObNVarchar2Type == data_type.get_obj_type()) &&
OB_MAX_ORACLE_VARCHAR_LENGTH < length) ||
(ObCharType == data_type.get_obj_type() && OB_MAX_ORACLE_CHAR_LENGTH_BYTE < length) ||
(ObNCharType == data_type.get_obj_type() &&
OB_MAX_ORACLE_CHAR_LENGTH_BYTE < length * nchar_mbminlen)) {
ret = OB_ERR_TOO_LONG_COLUMN_LENGTH;
LOG_WARN("column data length is invalid", K(ret), K(length), K(data_type), K(nchar_mbminlen));
LOG_USER_ERROR(OB_ERR_TOO_LONG_COLUMN_LENGTH,
ident_name.ptr(),
static_cast<int>(
(ObVarcharType == data_type.get_obj_type() || ObNVarchar2Type == data_type.get_obj_type())
? OB_MAX_ORACLE_VARCHAR_LENGTH
: OB_MAX_ORACLE_CHAR_LENGTH_BYTE));
} else if (type_node.length_semantics_ == LS_DEFAULT) {
data_type.set_length_semantics(nls_session_param.nls_length_semantics_);
} else if (OB_UNLIKELY(type_node.length_semantics_ != LS_BYTE && type_node.length_semantics_ != LS_CHAR)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("length_semantics_ is invalid", K(ret), K(type_node.length_semantics_));
} else {
data_type.set_length_semantics(type_node.length_semantics_);
}
data_type.set_charset_type(ObCharset::charset_type_by_coll(cs_type));
data_type.set_collation_type(cs_type);
LOG_DEBUG("check data type after resolve", K(ret), K(data_type));
} else {
// do nothing
}
break;
case ObRawTC:
data_type.set_length(length);
data_type.set_charset_type(CHARSET_BINARY);
data_type.set_collation_type(CS_TYPE_BINARY);
break;
case ObTextTC:
case ObLobTC:
data_type.set_length(length);
data_type.set_scale(default_accuracy.get_scale());
if (type_node.int32_values_[1] /*is binary*/) {
data_type.set_charset_type(CHARSET_BINARY);
data_type.set_collation_type(CS_TYPE_BINARY);
} else if (OB_FAIL(resolve_str_charset_info(type_node, data_type))) {
SQL_RESV_LOG(WARN, "fail to resolve string charset and collation", K(ret), K(data_type));
} else {
// do nothing
}
break;
case ObBitTC:
if (precision < 0) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("precision of bit is negative", K(ret), K(precision));
} else if (precision > OB_MAX_BIT_LENGTH) {
ret = OB_ERR_TOO_BIG_DISPLAYWIDTH;
LOG_USER_ERROR(OB_ERR_TOO_BIG_DISPLAYWIDTH, ident_name.ptr(), OB_MAX_BIT_LENGTH);
} else if (0 == precision) { // compatable with Mysql 5.6, 5.7 fails
data_type.set_precision(default_accuracy.get_precision());
data_type.set_scale(default_accuracy.get_scale());
} else {
data_type.set_precision(precision);
data_type.set_scale(default_accuracy.get_scale());
}
break;
case ObEnumSetTC:
if (OB_FAIL(resolve_str_charset_info(type_node, data_type))) {
LOG_WARN("fail to resolve column charset and collation", K(ident_name), K(ret));
}
break;
case ObIntervalTC:
if (data_type.get_meta_type().is_interval_ym()) {
if (0 == type_node.int16_values_[1]) {
data_type.set_scale(default_accuracy.get_scale());
} else {
if (!ObIntervalScaleUtil::scale_check(type_node.int16_values_[0])) {
ret = OB_ERR_DATETIME_INTERVAL_PRECISION_OUT_OF_RANGE;
} else {
ObScale scale =
ObIntervalScaleUtil::interval_ym_scale_to_ob_scale(static_cast<int8_t>(type_node.int16_values_[0]));
data_type.set_scale(scale);
}
}
} else { // interval ds
int8_t day_scale =
ObIntervalScaleUtil::ob_scale_to_interval_ds_day_scale(static_cast<int8_t>(default_accuracy.get_scale()));
int8_t fs_scale = ObIntervalScaleUtil::ob_scale_to_interval_ds_second_scale(
static_cast<int8_t>(default_accuracy.get_scale()));
if (OB_SUCC(ret) && 0 != type_node.int16_values_[1]) {
if (!ObIntervalScaleUtil::scale_check(type_node.int16_values_[0])) {
ret = OB_ERR_DATETIME_INTERVAL_PRECISION_OUT_OF_RANGE;
} else {
day_scale = static_cast<int8_t>(type_node.int16_values_[0]);
}
}
if (OB_SUCC(ret) && 0 != type_node.int16_values_[3]) {
if (!ObIntervalScaleUtil::scale_check(type_node.int16_values_[2])) {
ret = OB_ERR_DATETIME_INTERVAL_PRECISION_OUT_OF_RANGE;
} else {
fs_scale = static_cast<int8_t>(type_node.int16_values_[2]);
}
}
ObScale scale = ObIntervalScaleUtil::interval_ds_scale_to_ob_scale(day_scale, fs_scale);
data_type.set_scale(scale);
}
break;
case ObRowIDTC:
if (ob_is_urowid(data_type.get_obj_type())) {
if (length > OB_MAX_USER_ROW_KEY_LENGTH) {
ret = OB_ERR_TOO_LONG_COLUMN_LENGTH;
LOG_WARN("column data length is invalid", K(ret), K(length), K(data_type));
LOG_USER_ERROR(OB_ERR_TOO_LONG_COLUMN_LENGTH, ident_name.ptr(), static_cast<int>(OB_MAX_USER_ROW_KEY_LENGTH));
} else {
data_type.set_length(length);
}
} else {
ret = OB_NOT_SUPPORTED;
SQL_RESV_LOG(WARN, "only support urowid type for now", K(ret), K(data_type));
}
break;
case ObExtendTC:
// do nothing
break;
default:
ret = OB_ERR_ILLEGAL_TYPE;
SQL_RESV_LOG(WARN, "Unsupport data type of column definiton", K(ident_name), K(data_type), K(ret));
break;
}
LOG_DEBUG("resolve data type", K(ret), K(data_type), K(lbt()));
return ret;
}
int ObResolverUtils::resolve_str_charset_info(const ParseNode& type_node, ObDataType& data_type)
{
int ret = OB_SUCCESS;
bool is_binary = false;
ObString charset;
ObString collation;
ObCharsetType charset_type = CHARSET_INVALID;
ObCollationType collation_type = CS_TYPE_INVALID;
const ParseNode* charset_node = NULL;
const ParseNode* collation_node = NULL;
const ParseNode* binary_node = NULL;
if (OB_ISNULL(type_node.children_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("type node children is null");
} else {
charset_node = type_node.children_[0];
collation_node = type_node.children_[1];
binary_node = type_node.children_[2];
}
if (OB_SUCC(ret) && NULL != binary_node) {
is_binary = true;
}
if (OB_SUCC(ret) && NULL != charset_node) {
if (share::is_oracle_mode()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("set charset in oracle mode is not supported now", K(ret));
} else {
charset.assign_ptr(charset_node->str_value_, static_cast<int32_t>(charset_node->str_len_));
if (CHARSET_INVALID == (charset_type = ObCharset::charset_type(charset))) {
ret = OB_ERR_UNKNOWN_CHARSET;
LOG_USER_ERROR(OB_ERR_UNKNOWN_CHARSET, charset.length(), charset.ptr());
}
}
}
if (OB_SUCC(ret) && NULL != collation_node) {
if (share::is_oracle_mode()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("set collate in oracle mode is not supported now", K(ret));
} else {
collation.assign_ptr(collation_node->str_value_, static_cast<int32_t>(collation_node->str_len_));
if (CS_TYPE_INVALID == (collation_type = ObCharset::collation_type(collation))) {
ret = OB_ERR_UNKNOWN_COLLATION;
LOG_USER_ERROR(OB_ERR_UNKNOWN_COLLATION, collation.length(), collation.ptr());
}
}
}
if (OB_SUCC(ret)) {
data_type.set_charset_type(charset_type);
data_type.set_collation_type(collation_type);
data_type.set_binary_collation(is_binary);
}
return ret;
}
int ObResolverUtils::check_sync_ddl_user(ObSQLSessionInfo* session_info, bool& is_sync_ddl_user)
{
int ret = OB_SUCCESS;
is_sync_ddl_user = false;
if (OB_ISNULL(session_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Empty pointer session_info", K(ret));
} else {
const ObString current_user(session_info->get_user_name());
if (session_info->is_inner() || (ObCharset::case_insensitive_equal(current_user, OB_RESTORE_USER_NAME)) ||
(ObCharset::case_insensitive_equal(current_user, OB_DRC_USER_NAME))) {
is_sync_ddl_user = true;
} else {
is_sync_ddl_user = false;
}
}
return ret;
}
bool ObResolverUtils::is_restore_user(ObSQLSessionInfo& session_info)
{
int bret = false;
const ObString current_user(session_info.get_user_name());
if (ObCharset::case_insensitive_equal(current_user, OB_RESTORE_USER_NAME)) {
bret = true;
} else {
bret = false;
}
return bret;
}
bool ObResolverUtils::is_drc_user(ObSQLSessionInfo& session_info)
{
int bret = false;
const ObString current_user(session_info.get_user_name());
if (ObCharset::case_insensitive_equal(current_user, OB_DRC_USER_NAME)) {
bret = true;
} else {
bret = false;
}
return bret;
}
int ObResolverUtils::set_sync_ddl_id_str(ObSQLSessionInfo* session_info, ObString& ddl_id_str)
{
int ret = OB_SUCCESS;
ddl_id_str.reset();
bool is_sync_ddl_user = false;
if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info, is_sync_ddl_user))) {
LOG_WARN("Failed to check_sync_ddl_user", K(ret));
} else if (session_info->is_inner()) {
// do-nothing
} else if (is_sync_ddl_user) {
const ObString var_name(common::OB_DDL_ID_VAR_NAME);
common::ObObj var_obj;
if (OB_FAIL(session_info->get_user_variable_value(var_name, var_obj))) {
if (OB_ERR_USER_VARIABLE_UNKNOWN == ret) {
LOG_DEBUG("no __oceanbase_ddl_id user variable: ", K(ddl_id_str));
ret = OB_SUCCESS;
} else {
LOG_WARN("failed to get value of __oceanbase_ddl_id user variable", K(ret), K(var_name));
}
} else {
if (ob_is_string_type(var_obj.get_type())) {
ddl_id_str = var_obj.get_string();
LOG_DEBUG("__oceanbase_ddl_id user variable: ", K(ddl_id_str));
} else {
ret = OB_ERR_WRONG_TYPE_FOR_VAR;
LOG_WARN("data type of __oceanbase_ddl_id user variable is not string", K(ret), K(var_obj));
}
}
}
return ret;
}
// for create table with fk in oracle mode
int ObResolverUtils::check_dup_foreign_keys_exist(const common::ObSArray<obrpc::ObCreateForeignKeyArg>& fk_args)
{
int ret = OB_SUCCESS;
for (int i = 0; OB_SUCC(ret) && (i < fk_args.count() - 1); ++i) {
for (int j = i + 1; OB_SUCC(ret) && (j < fk_args.count()); ++j) {
if (0 == fk_args.at(i).parent_database_.case_compare(fk_args.at(j).parent_database_) &&
0 == fk_args.at(i).parent_table_.case_compare(fk_args.at(j).parent_table_)) {
if (is_match_columns_with_order(fk_args.at(i).child_columns_,
fk_args.at(i).parent_columns_,
fk_args.at(j).child_columns_,
fk_args.at(j).parent_columns_)) {
ret = OB_ERR_DUP_FK_IN_TABLE;
LOG_WARN("duplicate fks in table", K(ret), K(i), K(j), K(fk_args));
}
}
}
}
return ret;
}
// for alter table add fk in oracle mode
int ObResolverUtils::check_dup_foreign_keys_exist(const common::ObIArray<share::schema::ObForeignKeyInfo>& fk_infos,
const common::ObIArray<uint64_t>& child_column_ids, const common::ObIArray<uint64_t>& parent_column_ids,
const uint64_t parent_table_id)
{
int ret = OB_SUCCESS;
for (int i = 0; OB_SUCC(ret) && (i < fk_infos.count()); ++i) {
if (parent_table_id == fk_infos.at(i).parent_table_id_) {
if (is_match_columns_with_order(fk_infos.at(i).child_column_ids_,
fk_infos.at(i).parent_column_ids_,
child_column_ids,
parent_column_ids)) {
ret = OB_ERR_DUP_FK_EXISTS;
LOG_WARN("duplicate fk already exists in the table", K(ret), K(i), K(fk_infos.at(i)));
}
}
}
return ret;
}
int ObResolverUtils::foreign_key_column_match_uk_pk_column(const ObTableSchema& parent_table_schema,
ObSchemaChecker& schema_checker, ObIArray<ObString>& parent_columns, ObSArray<ObCreateIndexArg>& index_arg_list,
obrpc::ObCreateForeignKeyArg& arg, bool& is_match)
{
int ret = OB_SUCCESS;
is_match = false;
const ObRowkeyInfo& rowkey_info = parent_table_schema.get_rowkey_info();
common::ObSEArray<ObString, 8> pk_columns;
for (int64_t i = 0; OB_SUCC(ret) && i < rowkey_info.get_size(); ++i) {
uint64_t column_id = 0;
const ObColumnSchemaV2* col_schema = NULL;
if (OB_FAIL(rowkey_info.get_column_id(i, column_id))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("fail to get rowkey info", K(ret), K(i), K(rowkey_info));
} else if (NULL == (col_schema = parent_table_schema.get_column_schema(column_id))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get index column schema failed", K(ret));
} else if (col_schema->is_hidden() || col_schema->is_shadow_column()) {
// do nothing
} else if (OB_FAIL(pk_columns.push_back(col_schema->get_column_name()))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("push back index column failed", K(ret));
} else {
} // do nothing
}
if (OB_SUCC(ret)) {
if (OB_FAIL(check_match_columns(parent_columns, pk_columns, is_match))) {
LOG_WARN("Failed to check_match_columns", K(ret));
} else if (is_match) {
arg.ref_cst_type_ = CONSTRAINT_TYPE_PRIMARY_KEY;
for (ObTableSchema::const_constraint_iterator iter = parent_table_schema.constraint_begin();
iter != parent_table_schema.constraint_end();
++iter) {
if (CONSTRAINT_TYPE_PRIMARY_KEY == (*iter)->get_constraint_type()) {
arg.ref_cst_id_ = (*iter)->get_constraint_id();
break;
}
}
} else if (index_arg_list.count() > 0) {
for (int64_t i = 0; OB_SUCC(ret) && !is_match && i < index_arg_list.count(); ++i) {
ObCreateIndexArg index_arg;
if (OB_FAIL(index_arg.assign(index_arg_list.at(i)))) {
LOG_WARN("fail to assign schema", K(ret));
} else if (INDEX_TYPE_UNIQUE_LOCAL == index_arg.index_type_ ||
INDEX_TYPE_UNIQUE_GLOBAL == index_arg.index_type_) {
ObSEArray<ObString, 8> uk_columns;
for (int64_t j = 0; OB_SUCC(ret) && j < index_arg.index_columns_.count(); ++j) {
const ObColumnSortItem& sort_item = index_arg.index_columns_.at(j);
if (OB_FAIL(uk_columns.push_back(sort_item.column_name_))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("push back index column failed", K(ret), K(sort_item.column_name_));
}
}
if (OB_FAIL(check_match_columns(parent_columns, uk_columns, is_match))) {
LOG_WARN("Failed to check_match_columns", K(ret));
} else if (is_match) {
arg.ref_cst_type_ = CONSTRAINT_TYPE_UNIQUE_KEY;
}
}
}
} else {
ObSEArray<ObAuxTableMetaInfo, 16> simple_index_infos;
if (OB_FAIL(parent_table_schema.get_simple_index_infos_without_delay_deleted_tid(simple_index_infos))) {
LOG_WARN("get simple_index_infos without delay_deleted_tid failed", K(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && !is_match && i < simple_index_infos.count(); ++i) {
const ObTableSchema* index_table_schema = NULL;
if (OB_FAIL(schema_checker.get_table_schema(simple_index_infos.at(i).table_id_, index_table_schema))) {
LOG_WARN("get_table_schema failed", K(ret), "table id", simple_index_infos.at(i).table_id_);
} else if (OB_ISNULL(index_table_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("table schema should not be null", K(ret));
} else if (index_table_schema->is_unique_index()) {
const ObColumnSchemaV2* index_col = NULL;
const ObIndexInfo& index_info = index_table_schema->get_index_info();
ObSEArray<ObString, 8> uk_columns;
for (int64_t i = 0; OB_SUCC(ret) && i < index_info.get_size(); ++i) {
if (OB_ISNULL(index_col = index_table_schema->get_column_schema(index_info.get_column(i)->column_id_))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get index column schema failed", K(ret));
} else if (index_col->is_hidden() || index_col->is_shadow_column()) {
// do nothing
} else if (OB_FAIL(uk_columns.push_back(index_col->get_column_name()))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("push back index column failed", K(ret));
} else {
} // do nothing
}
if (OB_SUCC(ret)) {
if (OB_FAIL(check_match_columns(parent_columns, uk_columns, is_match))) {
LOG_WARN("Failed to check_match_columns", K(ret));
} else if (is_match) {
arg.ref_cst_type_ = CONSTRAINT_TYPE_UNIQUE_KEY;
arg.ref_cst_id_ = index_table_schema->get_table_id();
}
}
}
}
}
}
return ret;
}
bool ObResolverUtils::is_match_columns_with_order(const common::ObIArray<ObString>& child_columns_1,
const common::ObIArray<ObString>& parent_columns_1, const common::ObIArray<ObString>& child_columns_2,
const common::ObIArray<ObString>& parent_columns_2)
{
bool dup_foreign_keys_exist = true;
if (child_columns_1.count() != child_columns_2.count()) {
dup_foreign_keys_exist = false;
} else {
for (int i = 0; dup_foreign_keys_exist && (i < child_columns_1.count()); ++i) {
int j = 0;
bool find_same_child_column = false;
for (j = 0; !find_same_child_column && (j < child_columns_2.count()); ++j) {
if (0 == child_columns_1.at(i).case_compare(child_columns_2.at(j))) {
find_same_child_column = true;
if (0 != parent_columns_1.at(i).case_compare(parent_columns_2.at(j))) {
dup_foreign_keys_exist = false;
}
}
}
if (!find_same_child_column) {
dup_foreign_keys_exist = false;
}
}
}
return dup_foreign_keys_exist;
}
bool ObResolverUtils::is_match_columns_with_order(const common::ObIArray<uint64_t>& child_column_ids_1,
const common::ObIArray<uint64_t>& parent_column_ids_1, const common::ObIArray<uint64_t>& child_column_ids_2,
const common::ObIArray<uint64_t>& parent_column_ids_2)
{
bool dup_foreign_keys_exist = true;
if (child_column_ids_1.count() != child_column_ids_2.count()) {
dup_foreign_keys_exist = false;
} else {
for (int i = 0; dup_foreign_keys_exist && (i < child_column_ids_1.count()); ++i) {
int j = 0;
bool find_same_child_column = false;
for (j = 0; !find_same_child_column && (j < child_column_ids_2.count()); ++j) {
if (child_column_ids_1.at(i) == child_column_ids_2.at(j)) {
find_same_child_column = true;
if (parent_column_ids_1.at(i) != parent_column_ids_2.at(j)) {
dup_foreign_keys_exist = false;
}
}
}
if (!find_same_child_column) {
dup_foreign_keys_exist = false;
}
}
}
return dup_foreign_keys_exist;
}
int ObResolverUtils::check_match_columns(
const ObIArray<ObString>& parent_columns, const ObIArray<ObString>& key_columns, bool& is_match)
{
int ret = OB_SUCCESS;
is_match = false;
ObSEArray<ObString, 8> tmp_parent_columns;
ObSEArray<ObString, 8> tmp_key_columns;
if (parent_columns.count() == key_columns.count() && parent_columns.count() > 0) {
for (int64_t i = 0; OB_SUCC(ret) && i < parent_columns.count(); ++i) {
if (OB_FAIL(tmp_parent_columns.push_back(parent_columns.at(i)))) {
LOG_WARN("fail to push back", K(ret));
} else if (OB_FAIL(tmp_key_columns.push_back(key_columns.at(i)))) {
LOG_WARN("fail to push back", K(ret));
}
}
if (OB_SUCC(ret)) {
if (tmp_parent_columns.count() == tmp_key_columns.count() && tmp_parent_columns.count() > 0) {
std::sort(tmp_parent_columns.begin(), tmp_parent_columns.end());
std::sort(tmp_key_columns.begin(), tmp_key_columns.end());
bool is_tmp_match = true;
for (int64_t i = 0; is_tmp_match && i < tmp_parent_columns.count(); ++i) {
if (0 != tmp_parent_columns.at(i).case_compare(tmp_key_columns.at(i))) {
is_tmp_match = false;
}
}
if (is_tmp_match) {
is_match = true;
}
}
}
}
return ret;
}
int ObResolverUtils::check_match_columns_strict(
const ObIArray<ObString>& columns_array_1, const ObIArray<ObString>& columns_array_2, bool& is_match)
{
int ret = OB_SUCCESS;
bool is_tmp_match = true;
is_match = false;
if (columns_array_1.count() == columns_array_2.count() && columns_array_1.count() > 0) {
for (int64_t i = 0; is_tmp_match && i < columns_array_1.count(); ++i) {
if (0 != columns_array_1.at(i).case_compare(columns_array_2.at(i))) {
is_tmp_match = false;
}
}
if (is_tmp_match) {
is_match = true;
}
}
return ret;
}
int ObResolverUtils::check_match_columns_strict_with_order(
const ObTableSchema* index_table_schema, const ObCreateIndexArg& create_index_arg, bool& is_match)
{
int ret = OB_SUCCESS;
bool is_tmp_match = true;
ObString tmp_col_name_1;
ObString tmp_col_name_2;
ObOrderType tmp_order_type_1;
ObOrderType tmp_order_type_2;
const ObColumnSchemaV2* tmp_index_col = NULL;
const ObIndexInfo& index_info = index_table_schema->get_index_info();
is_match = false;
if (index_info.get_size() == create_index_arg.index_columns_.count() && create_index_arg.index_columns_.count() > 0) {
for (int64_t idx = 0; is_tmp_match && idx < index_info.get_size(); ++idx) {
if (OB_ISNULL(tmp_index_col = index_table_schema->get_column_schema(index_info.get_column(idx)->column_id_))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get index column schema failed", K(ret));
} else {
tmp_col_name_1 = tmp_index_col->get_column_name_str();
tmp_order_type_1 = tmp_index_col->get_order_in_rowkey();
tmp_col_name_2 = create_index_arg.index_columns_.at(idx).column_name_;
tmp_order_type_2 = create_index_arg.index_columns_.at(idx).order_type_;
if ((0 != tmp_col_name_1.case_compare(tmp_col_name_2)) || (tmp_order_type_1 != tmp_order_type_2)) {
is_tmp_match = false;
}
}
}
if (is_tmp_match) {
is_match = true;
}
}
return ret;
}
int ObResolverUtils::check_pk_idx_duplicate(const ObTableSchema& table_schema, const ObCreateIndexArg& create_index_arg,
const ObIArray<ObString>& input_uk_columns_name, bool& is_match)
{
int ret = OB_SUCCESS;
const ObRowkeyInfo& rowkey = table_schema.get_rowkey_info();
const ObColumnSchemaV2* column = NULL;
uint64_t column_id = OB_INVALID_ID;
ObSEArray<ObString, 8> pk_columns_name;
is_match = false;
const bool is_multi_pk_for_heap_table = table_schema.is_new_no_pk_table() && rowkey.get_size() > 1;
// generate pk_columns_name_array
for (int64_t rowkey_idx = 0; rowkey_idx < rowkey.get_size(); ++rowkey_idx) {
if (OB_FAIL(rowkey.get_column_id(rowkey_idx, column_id))) {
LOG_WARN("fail to get column id", K(ret));
} else if (OB_ISNULL(column = table_schema.get_column_schema(column_id))) {
LOG_WARN("fail to get column schema", K(ret), K(column_id), K(rowkey));
} else if (column->is_hidden() && !is_multi_pk_for_heap_table) {
// skip hidden pk col
} else if (OB_FAIL(pk_columns_name.push_back(column->get_column_name_str()))) {
LOG_WARN("fail to push back to pk_columns_name array",
K(ret),
K(rowkey_idx),
K(column_id),
K(column->get_column_name_str()));
}
}
// check if pk uk duplicate
if (OB_SUCC(ret) && rowkey.get_size() != 0) {
if (OB_FAIL(ObResolverUtils::check_match_columns_strict(input_uk_columns_name, pk_columns_name, is_match))) {
LOG_WARN("Failed to check_match_columns", K(ret));
} else if (is_match) {
for (int64_t i = 0; is_match && i < create_index_arg.index_columns_.count(); ++i) {
if (ObOrderType::DESC == create_index_arg.index_columns_.at(i).order_type_) {
is_match = false;
}
}
}
}
return ret;
}
int ObResolverUtils::check_foreign_key_columns_type(const ObTableSchema& child_table_schema,
const ObTableSchema& parent_table_schema, ObIArray<ObString>& child_columns, ObIArray<ObString>& parent_columns,
const share::schema::ObColumnSchemaV2* column)
{
int ret = OB_SUCCESS;
if (child_columns.count() != parent_columns.count()) {
ret = OB_ERR_WRONG_FK_DEF;
LOG_WARN("the count of foreign key columns is not equal to the count of reference columns",
K(ret),
K(child_columns.count()),
K(parent_columns.count()));
} else if (child_columns.count() > OB_USER_MAX_ROWKEY_COLUMN_NUMBER) {
ret = OB_ERR_TOO_MANY_ROWKEY_COLUMNS;
LOG_USER_ERROR(OB_ERR_TOO_MANY_ROWKEY_COLUMNS, OB_USER_MAX_ROWKEY_COLUMN_NUMBER);
LOG_WARN("the count of foreign key columns should be between [1,64]",
K(ret),
K(child_columns.count()),
K(parent_columns.count()));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < parent_columns.count(); ++i) {
const ObColumnSchemaV2* child_col = NULL;
const ObColumnSchemaV2* parent_col = parent_table_schema.get_column_schema(parent_columns.at(i));
if (NULL == column) { // table-level fk
child_col = child_table_schema.get_column_schema(child_columns.at(i));
} else { // column level fk
child_col = column;
}
if (OB_FAIL(ret)) {
} else if (OB_ISNULL(child_col)) {
ret = OB_ERR_COLUMN_NOT_FOUND;
LOG_WARN("child column is not exist", K(ret));
} else if (OB_ISNULL(parent_col)) {
ret = OB_ERR_COLUMN_NOT_FOUND;
LOG_WARN("parent column is not exist", K(ret));
} else if ((child_col->get_data_type() != parent_col->get_data_type()) &&
!is_synonymous_type(child_col->get_data_type(), parent_col->get_data_type())) {
ret = OB_ERR_CANNOT_ADD_FOREIGN;
LOG_WARN("Column data types between child table and parent table are different",
K(ret),
K(child_col->get_data_type()),
K(parent_col->get_data_type()));
} else if (child_col->is_virtual_generated_column() || parent_col->is_virtual_generated_column()) {
ret = OB_ERR_CANNOT_ADD_FOREIGN;
LOG_WARN("cannot create foreign key based on virtual generated columns", K(ret));
} else if (share::is_mysql_mode() &&
(ob_is_float_tc(child_col->get_data_type()) || ob_is_double_tc(child_col->get_data_type()) ||
ob_is_number_tc(child_col->get_data_type()))) {
if (child_col->get_data_precision() < parent_col->get_data_precision() ||
child_col->get_data_scale() < parent_col->get_data_scale()) {
ret = OB_ERR_INVALID_CHILD_COLUMN_LENGTH_FK;
LOG_USER_ERROR(OB_ERR_INVALID_CHILD_COLUMN_LENGTH_FK,
child_col->get_column_name_str().length(),
child_col->get_column_name_str().ptr(),
parent_col->get_column_name_str().length(),
parent_col->get_column_name_str().ptr());
}
} else if (ob_is_string_type(child_col->get_data_type())) {
if (child_col->get_collation_type() != parent_col->get_collation_type()) {
ret = OB_ERR_CANNOT_ADD_FOREIGN;
LOG_WARN("The collation types are different",
K(ret),
K(child_col->get_collation_type()),
K(parent_col->get_collation_type()));
} else if (share::is_mysql_mode() && (child_col->get_data_length() < parent_col->get_data_length())) {
ret = OB_ERR_INVALID_CHILD_COLUMN_LENGTH_FK;
LOG_USER_ERROR(OB_ERR_INVALID_CHILD_COLUMN_LENGTH_FK,
child_col->get_column_name_str().length(),
child_col->get_column_name_str().ptr(),
parent_col->get_column_name_str().length(),
parent_col->get_column_name_str().ptr());
} else {
}
}
}
}
return ret;
}
int ObResolverUtils::transform_func_sys_to_udf(ObIAllocator* allocator, const ParseNode* func_sys,
const ObString& db_name, const ObString& pkg_name, ParseNode*& func_udf)
{
int ret = OB_SUCCESS;
ParseNode* db_name_node = NULL;
ParseNode* pkg_name_node = NULL;
func_udf = NULL;
if (OB_ISNULL(allocator) || OB_ISNULL(func_sys)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("allocator or sys func node is null", K(ret));
} else if (OB_ISNULL(func_udf = new_non_terminal_node(allocator, T_FUN_UDF, 4, nullptr, nullptr, nullptr, nullptr))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("make T_FUN_UDF node failed", K(ret));
} else {
// assign db name node
if (!db_name.empty()) {
if (OB_ISNULL(db_name_node = new_terminal_node(allocator, T_IDENT))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("make db name T_IDENT node failed", K(ret));
} else {
func_udf->children_[2] = db_name_node;
db_name_node->str_value_ = parse_strndup(db_name.ptr(), db_name.length(), allocator);
if (OB_ISNULL(db_name_node->str_value_)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("copy db name failed", K(ret));
} else {
db_name_node->str_len_ = db_name.length();
}
}
}
// assign pkg name node
if (!pkg_name.empty()) {
if (OB_ISNULL(pkg_name_node = new_terminal_node(allocator, T_IDENT))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("make pkg name T_IDENT node failed", K(ret));
} else {
func_udf->children_[3] = pkg_name_node;
pkg_name_node->str_value_ = parse_strndup(pkg_name.ptr(), pkg_name.length(), allocator);
if (OB_ISNULL(pkg_name_node->str_value_)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("copy pkg name failed", K(ret));
} else {
pkg_name_node->str_len_ = pkg_name.length();
}
}
}
if (OB_SUCC(ret)) {
// sys node and udf node have the same memory life cycle
// we share the func name and param node;
func_udf->children_[0] = func_sys->children_[0]; // func name
if (2 == func_sys->num_child_) {
func_udf->children_[1] = func_sys->children_[1]; // func param
} else {
func_udf->children_[1] = NULL;
}
}
}
return ret;
}
int ObResolverUtils::get_columns_name_from_index_table_schema(
const ObTableSchema& index_table_schema, ObIArray<ObString>& index_columns_name)
{
int ret = OB_SUCCESS;
const ObColumnSchemaV2* index_col = NULL;
const ObIndexInfo& index_info = index_table_schema.get_index_info();
index_columns_name.reset();
for (int64_t i = 0; OB_SUCC(ret) && i < index_info.get_size(); ++i) {
if (OB_ISNULL(index_col = index_table_schema.get_column_schema(index_info.get_column(i)->column_id_))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get index column schema failed", K(ret));
} else if (index_col->is_hidden() || index_col->is_shadow_column()) {
// do nothing
} else if (OB_FAIL(index_columns_name.push_back(index_col->get_column_name()))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("push back index column failed", K(ret));
} else {
} // do nothing
}
return ret;
}
int ObResolverUtils::resolve_string(const ParseNode* node, ObString& string)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(NULL == node)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node should not be null");
} else if (OB_UNLIKELY(T_VARCHAR != node->type_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node type is not T_VARCHAR", "type", get_type_name(node->type_));
} else if (OB_UNLIKELY(node->str_len_ <= 0)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("empty string");
} else {
string = ObString(node->str_len_, node->str_value_);
}
return ret;
}
int ObResolverUtils::resolve_external_param_info(ObIArray<std::pair<ObRawExpr*, ObConstRawExpr*>>& param_infos,
ObRawExprFactory& expr_factory, int64_t& prepare_param_count, ObRawExpr*& expr)
{
int ret = OB_SUCCESS;
int64_t same_idx = OB_INVALID_INDEX;
for (int64_t i = 0; OB_SUCC(ret) && OB_INVALID_INDEX == same_idx && i < param_infos.count(); ++i) {
ObRawExpr* original_expr = param_infos.at(i).first;
if (OB_ISNULL(original_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is NULL", K(ret));
} else if (original_expr->same_as(*expr)) {
same_idx = i;
} else { /*do nothing*/
}
}
if (OB_SUCC(ret)) {
if (OB_INVALID_INDEX != same_idx) {
expr = param_infos.at(same_idx).second;
} else {
std::pair<ObRawExpr*, ObConstRawExpr*> param_info;
ObRawExpr* original_ref = expr;
if (OB_FAIL(ObRawExprUtils::create_param_expr(expr_factory, prepare_param_count++, expr))) {
LOG_WARN("create param expr failed", K(ret));
} else if (OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("access idxs is empty", K(ret));
} else {
ObConstRawExpr* param_expr = static_cast<ObConstRawExpr*>(expr);
const_cast<sql::ObExprResType&>(param_expr->get_result_type()).set_param(param_expr->get_value());
param_info.first = original_ref;
param_info.second = param_expr;
if (OB_FAIL(param_infos.push_back(param_info))) {
LOG_WARN("push_back error", K(ret));
}
}
}
}
return ret;
}
int ObResolverUtils::uv_check_basic(ObSelectStmt& stmt, const bool is_insert)
{
int ret = OB_SUCCESS;
if (stmt.get_table_items().count() == 0) {
// create view as select 1 a;
ret = lib::is_mysql_mode() ? (is_insert ? OB_ERR_NON_INSERTABLE_TABLE : OB_ERR_NON_UPDATABLE_TABLE)
: OB_ERR_ILLEGAL_VIEW_UPDATE;
LOG_WARN("no table in select", K(ret));
} else {
if (lib::is_mysql_mode()) {
if (stmt.has_group_by() || stmt.has_having() || stmt.get_aggr_item_size() > 0 || stmt.has_window_function() ||
stmt.is_distinct() || stmt.has_set_op() || stmt.has_limit()) {
ret = is_insert ? OB_ERR_NON_INSERTABLE_TABLE : OB_ERR_NON_UPDATABLE_TABLE;
LOG_WARN("not updatable", K(ret));
}
} else if (stmt.has_fetch()) {
ret = OB_ERR_VIRTUAL_COL_NOT_ALLOWED;
LOG_WARN("subquery with fetch can't occur in insert/update/delete stmt", K(ret));
} else {
bool has_rownum = false;
if (OB_FAIL(stmt.has_rownum(has_rownum))) {
LOG_WARN("check select stmt has rownum failed", K(ret));
}
if (stmt.has_window_function() || stmt.has_set_op() || has_rownum ||
(!is_insert && (stmt.has_group_by() || stmt.has_having() || stmt.get_aggr_item_size() > 0))) {
ret = OB_ERR_ILLEGAL_VIEW_UPDATE;
LOG_WARN("not updatable", K(ret));
}
}
}
return ret;
}
int ObResolverUtils::check_select_item_subquery(ObSelectStmt& stmt, bool& has_subquery, bool& has_dependent_subquery,
const uint64_t base_tid, bool& ref_update_table)
{
int ret = OB_SUCCESS;
ObSEArray<ObQueryRefRawExpr*, 1> query_exprs;
FOREACH_CNT_X(item, stmt.get_select_items(), OB_SUCC(ret))
{
if (OB_ISNULL(item->expr_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is NULL", K(ret));
} else if (OB_FAIL(ObTransformUtils::extract_query_ref_expr(item->expr_, query_exprs))) {
LOG_WARN("extract sub query expr failed", K(ret));
}
}
if (OB_SUCC(ret) && query_exprs.count() > 0) {
has_subquery = true;
FOREACH_CNT_X(expr, query_exprs, OB_SUCC(ret) && !has_dependent_subquery)
{
if (OB_ISNULL(*expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is NULL", K(ret));
} else {
ObSelectStmt* ref_stmt = (*expr)->get_ref_stmt();
if (NULL != ref_stmt) {
FOREACH_CNT_X(item, ref_stmt->get_table_items(), OB_SUCC(ret) && !ref_update_table)
{
if (OB_ISNULL(*item)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL table item", K(ret));
} else if ((*item)->ref_id_ == base_tid) {
ref_update_table = true;
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(ObTransformUtils::is_ref_outer_block_relation(
ref_stmt, ref_stmt->get_current_level(), has_dependent_subquery))) {
LOG_WARN("check subquery ref outer relation failed", K(ret));
}
}
}
}
}
return ret;
}
int ObResolverUtils::set_direction_by_mode(const ParseNode& sort_node, OrderItem& order_item)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(sort_node.children_) || sort_node.num_child_ < 2 || OB_ISNULL(sort_node.children_[1])) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret));
} else if (T_SORT_ASC == sort_node.children_[1]->type_) {
if (share::is_oracle_mode()) {
if (1 == sort_node.children_[1]->value_) {
order_item.order_type_ = NULLS_LAST_ASC;
} else if (2 == sort_node.children_[1]->value_) {
order_item.order_type_ = NULLS_FIRST_ASC;
} else {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid value for null position", K(ret), K(sort_node.children_[1]->value_));
}
} else {
order_item.order_type_ = NULLS_FIRST_ASC;
}
} else if (T_SORT_DESC == sort_node.children_[1]->type_) {
if (share::is_oracle_mode()) {
if (1 == sort_node.children_[1]->value_) {
order_item.order_type_ = NULLS_LAST_DESC;
} else if (2 == sort_node.children_[1]->value_) {
order_item.order_type_ = NULLS_FIRST_DESC;
} else {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid value for null position", K(ret), K(sort_node.children_[1]->value_));
}
} else {
order_item.order_type_ = NULLS_LAST_DESC;
}
} else {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid sort type", K(ret), K(sort_node.children_[1]->type_));
}
return ret;
}
int ObResolverUtils::uv_check_select_item_subquery(
const TableItem& table_item, bool& has_subquery, bool& has_dependent_subquery, bool& ref_update_table)
{
int ret = OB_SUCCESS;
const TableItem* item = &table_item;
const uint64_t base_tid = table_item.get_base_table_item().ref_id_;
while (OB_SUCC(ret) && NULL != item && item->is_generated_table() && !has_dependent_subquery) {
if (OB_ISNULL(item->ref_query_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("ref query is NULL for generate table", K(ret));
} else if (OB_FAIL(check_select_item_subquery(
*item->ref_query_, has_subquery, has_dependent_subquery, base_tid, ref_update_table))) {
LOG_WARN("check select item subquery failed", K(ret));
} else {
item = item->view_base_item_;
}
}
return ret;
}
int ObResolverUtils::check_table_referred(ObSelectStmt& stmt, const uint64_t base_tid, bool& referred)
{
int ret = OB_SUCCESS;
OZ(check_stack_overflow());
FOREACH_CNT_X(t, stmt.get_table_items(), OB_SUCC(ret) && !referred)
{
if (OB_ISNULL(*t)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("table item is NULL", K(ret));
} else {
if ((*t)->ref_id_ == base_tid) {
referred = true;
} else if ((*t)->is_generated_table() && NULL != (*t)->ref_query_) {
if (OB_FAIL(check_table_referred(*(*t)->ref_query_, base_tid, referred))) {
LOG_WARN("check table referred failed", K(ret));
}
}
}
}
FOREACH_CNT_X(expr, stmt.get_subquery_exprs(), OB_SUCC(ret) && !referred)
{
if (OB_ISNULL(*expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is NULL", K(ret));
} else if (NULL != (*expr)->get_ref_stmt()) {
if (OB_FAIL(check_table_referred(*(*expr)->get_ref_stmt(), base_tid, referred))) {
LOG_WARN("check table referred in subquery failed", K(ret));
}
}
}
return ret;
}
int ObResolverUtils::uv_check_where_subquery(const TableItem& table_item, bool& ref_update_table)
{
int ret = OB_SUCCESS;
const TableItem* item = &table_item;
uint64_t update_tid = table_item.get_base_table_item().ref_id_;
ObSEArray<ObQueryRefRawExpr*, 1> query_exprs;
while (OB_SUCC(ret) && NULL != item && item->is_generated_table()) {
if (OB_ISNULL(item->ref_query_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("ref query is NULL for generate table", K(ret));
} else {
FOREACH_CNT_X(expr, item->ref_query_->get_condition_exprs(), OB_SUCC(ret))
{
if (OB_ISNULL(*expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is NULL", K(ret));
} else if (OB_FAIL(ObTransformUtils::extract_query_ref_expr(*expr, query_exprs))) {
LOG_WARN("extract subquery failed", K(ret));
}
}
}
item = item->view_base_item_;
}
FOREACH_CNT_X(expr, query_exprs, OB_SUCC(ret) && !ref_update_table)
{
if (OB_ISNULL(*expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is NULL", K(ret));
} else if (NULL != (*expr)->get_ref_stmt()) {
if (OB_FAIL(check_table_referred(*(*expr)->get_ref_stmt(), update_tid, ref_update_table))) {
LOG_WARN("check table referred in subquery failed", K(ret));
}
}
}
return ret;
}
int ObResolverUtils::check_has_non_inner_join(ObSelectStmt& stmt, bool& has_non_inner_join)
{
int ret = OB_SUCCESS;
FOREACH_CNT_X(join, stmt.get_joined_tables(), !has_non_inner_join)
{
if (OB_ISNULL(*join)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("join table is NULL", K(ret));
} else if (!(*join)->is_inner_join()) {
has_non_inner_join = true;
}
}
return ret;
}
int ObResolverUtils::uv_check_has_non_inner_join(const TableItem& table_item, bool& has_non_inner_join)
{
int ret = OB_SUCCESS;
const TableItem* item = &table_item;
while (OB_SUCC(ret) && NULL != item && item->is_generated_table() && !has_non_inner_join) {
if (OB_ISNULL(item->ref_query_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("ref query is NULL for generate table", K(ret));
} else if (OB_FAIL(check_has_non_inner_join(*item->ref_query_, has_non_inner_join))) {
LOG_WARN("check select item subquery failed", K(ret));
} else {
item = item->view_base_item_;
}
}
return ret;
}
int ObResolverUtils::uv_check_dup_base_col(const TableItem& table_item, bool& has_dup, bool& has_non_col_ref)
{
int ret = OB_SUCCESS;
has_dup = false;
has_non_col_ref = false;
if (table_item.is_generated_table() && NULL != table_item.ref_query_) {
const uint64_t base_tid = table_item.get_base_table_item().ref_id_;
const ObIArray<SelectItem>& select_items = table_item.ref_query_->get_select_items();
ObSEArray<int64_t, 32> cids;
FOREACH_CNT_X(si, select_items, OB_SUCC(ret) && !has_dup)
{
if (si->implicit_filled_) {
continue;
}
ObRawExpr* expr = si->expr_;
if (T_REF_ALIAS_COLUMN == expr->get_expr_type()) {
expr = static_cast<ObAliasRefRawExpr*>(expr)->get_ref_expr();
}
if (T_REF_COLUMN != expr->get_expr_type()) {
has_non_col_ref = true;
} else {
ColumnItem* col_item =
table_item.ref_query_->get_column_item_by_id(static_cast<ObColumnRefRawExpr*>(expr)->get_table_id(),
static_cast<ObColumnRefRawExpr*>(expr)->get_column_id());
if (OB_ISNULL(col_item)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get column item by id failed", K(ret), K(*expr));
} else if (base_tid == col_item->base_tid_) {
FOREACH_X(c, cids, !has_dup)
{
if (*c == col_item->base_cid_) {
has_dup = true;
}
}
if (OB_FAIL(cids.push_back(col_item->base_cid_))) {
LOG_WARN("array push back failed", K(ret));
}
}
}
}
}
return ret;
}
// mysql insertable view:
// 1. must be inner join
// 2. all join components:
// - must be view
// - can not reference the update table
// - pass uv_check_basic
int ObResolverUtils::uv_mysql_insertable_join(const TableItem& table_item, const uint64_t base_tid, bool& insertable)
{
int ret = OB_SUCCESS;
if (table_item.is_generated_table() && NULL != table_item.ref_query_) {
OZ(check_stack_overflow());
FOREACH_CNT_X(join, table_item.ref_query_->get_joined_tables(), OB_SUCC(ret) && insertable)
{
if (OB_ISNULL(*join)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("join table is NULL", K(ret));
} else if (!(*join)->is_inner_join()) {
insertable = false;
}
}
FOREACH_CNT_X(it, table_item.ref_query_->get_table_items(), OB_SUCC(ret) && insertable)
{
const TableItem* item = *it;
if (OB_ISNULL(item)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("null join table item", K(ret));
} else if (item->is_basic_table()) {
if (table_item.view_base_item_ != item && item->ref_id_ == base_tid) {
LOG_DEBUG("reference to insert table");
insertable = false;
}
} else if (item->is_generated_table()) {
if (OB_ISNULL(item->ref_query_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("ref query is NULL", K(ret));
}
if (OB_SUCC(ret) && insertable) {
if (!item->is_view_table_) {
insertable = false;
}
}
if (OB_SUCC(ret) && insertable && item != table_item.view_base_item_) {
bool ref = false;
if (OB_FAIL(check_table_referred(*item->ref_query_, base_tid, ref))) {
LOG_WARN("check table referred failed", K(ret));
} else if (ref) {
insertable = false;
}
}
if (OB_SUCC(ret) && insertable) {
const bool is_insert = true;
int tmp_ret = uv_check_basic(*item->ref_query_, is_insert);
if (OB_SUCCESS != tmp_ret) {
if (tmp_ret == OB_ERR_NON_INSERTABLE_TABLE) {
insertable = false;
} else {
ret = tmp_ret;
LOG_WARN("check basic updatable view failed", K(ret));
}
}
}
if (OB_SUCC(ret) && insertable) {
if (OB_FAIL(uv_mysql_insertable_join(*item, base_tid, insertable))) {
LOG_WARN("check insertable join failed", K(ret));
}
}
}
} // end FOREACH
}
return ret;
}
int ObResolverUtils::uv_check_oracle_distinct(
const TableItem& table_item, ObSQLSessionInfo& session_info, ObSchemaChecker& schema_checker, bool& has_distinct)
{
int ret = OB_SUCCESS;
has_distinct = false;
const TableItem* item = &table_item;
ObSEArray<ObRawExpr*, 16> select_exprs;
while (NULL != item && item->is_generated_table() && NULL != item->ref_query_ && !has_distinct) {
if (item->ref_query_->has_distinct()) {
bool unique = false;
select_exprs.reuse();
// Can not call ObOptimizerUtil::get_select_exprs(),
// since we need ignore implicit filled select items.
FOREACH_CNT_X(si, item->ref_query_->get_select_items(), OB_SUCC(ret))
{
if (OB_ISNULL(si->expr_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr is NULL in select item", K(ret));
} else {
if (!si->implicit_filled_) {
if (OB_FAIL(select_exprs.push_back(si->expr_))) {
LOG_WARN("array push back failed", K(ret));
}
}
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(ObTransformUtils::check_stmt_unique(item->ref_query_,
&session_info,
&schema_checker,
select_exprs,
true /* strict */,
unique,
FLAGS_IGNORE_DISTINCT /* ignore distinct */))) {
LOG_WARN("check stmt unique failed", K(ret));
} else {
// distinct will be removed latter if unique.
has_distinct = !unique;
}
}
item = item->view_base_item_;
}
return ret;
}
ObString ObResolverUtils::get_stmt_type_string(stmt::StmtType stmt_type)
{
return ((stmt::T_NONE <= stmt_type && stmt_type <= stmt::T_MAX) ? stmt_type_string[stmt::get_stmt_type_idx(stmt_type)]
: ObString::make_empty_string());
}
ParseNode* ObResolverUtils::get_select_into_node(const ParseNode& node)
{
ParseNode* into_node = NULL;
if (OB_LIKELY(node.type_ == T_SELECT)) {
if (NULL != node.children_[PARSE_SELECT_INTO]) {
into_node = node.children_[PARSE_SELECT_INTO];
} else {
into_node = node.children_[PARSE_SELECT_INTO_EXTRA];
}
}
return into_node;
}
int ObResolverUtils::parse_interval_ym_type(char* cstr, ObDateUnitType& part_type)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(cstr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("data is null", K(ret));
} else if (OB_NOT_NULL(strcasestr(cstr, ob_date_unit_type_str(DATE_UNIT_YEAR)))) {
part_type = DATE_UNIT_YEAR;
} else if (OB_NOT_NULL(strcasestr(cstr, ob_date_unit_type_str(DATE_UNIT_MONTH)))) {
part_type = DATE_UNIT_MONTH;
} else {
part_type = DATE_UNIT_MAX;
}
return ret;
}
int ObResolverUtils::parse_interval_ds_type(char* cstr, ObDateUnitType& part_type)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(cstr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("data is null", K(ret));
} else if (OB_NOT_NULL(strcasestr(cstr, ob_date_unit_type_str(DATE_UNIT_DAY)))) {
part_type = DATE_UNIT_DAY;
} else if (OB_NOT_NULL(strcasestr(cstr, ob_date_unit_type_str(DATE_UNIT_HOUR)))) {
part_type = DATE_UNIT_HOUR;
} else if (OB_NOT_NULL(strcasestr(cstr, ob_date_unit_type_str(DATE_UNIT_MINUTE)))) {
part_type = DATE_UNIT_MINUTE;
} else if (OB_NOT_NULL(strcasestr(cstr, ob_date_unit_type_str(DATE_UNIT_SECOND)))) {
part_type = DATE_UNIT_SECOND;
} else {
part_type = DATE_UNIT_MAX;
}
return ret;
}
int ObResolverUtils::parse_interval_precision(char* cstr, int16_t& precision, int16_t default_precision)
{
int ret = OB_SUCCESS;
const char* brackt_pos1 = strchr(cstr, '(');
const char* brackt_pos2 = strchr(cstr, ')');
if (OB_NOT_NULL(brackt_pos1) && OB_NOT_NULL(brackt_pos2)) {
precision = atoi(brackt_pos1 + 1);
} else {
precision = default_precision;
}
return ret;
}
int ObResolverUtils::get_user_var_value(const ParseNode* node, ObSQLSessionInfo* session_info, ObObj& value)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(node) || OB_ISNULL(session_info)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(node), K(session_info));
} else 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 get user_val", K(ret), K(node->num_child_));
} else {
ObString str = ObString(static_cast<int32_t>(node->children_[0]->str_len_), node->children_[0]->str_value_);
ObSessionVariable osv;
ret = session_info->get_user_variable(str, osv);
if (OB_SUCC(ret)) {
value = osv.value_;
value.set_meta_type(osv.meta_);
} else if (OB_ERR_USER_VARIABLE_UNKNOWN == ret) {
value.set_null();
value.set_collation_level(CS_LEVEL_IMPLICIT);
ret = OB_SUCCESS; // always return success no matter found or not
} else {
LOG_WARN("Unexpected ret code", K(ret), K(str), K(osv));
}
}
return ret;
}
int ObResolverUtils::check_duplicated_column(ObSelectStmt& select_stmt, bool can_skip /*default false*/)
{
int ret = OB_SUCCESS;
if (!can_skip) {
for (int64_t i = 1; OB_SUCC(ret) && i < select_stmt.get_select_item_size(); i++) {
for (int64_t j = 0; OB_SUCC(ret) && j < i; ++j) {
if (ObCharset::case_compat_mode_equal(
select_stmt.get_select_item(i).alias_name_, select_stmt.get_select_item(j).alias_name_)) {
if (share::is_oracle_mode()) {
ret = OB_NON_UNIQ_ERROR;
ObString scope_name = ObString::make_string(get_scope_name(T_FIELD_LIST_SCOPE));
LOG_USER_ERROR(OB_NON_UNIQ_ERROR,
select_stmt.get_select_item(i).alias_name_.length(),
select_stmt.get_select_item(i).alias_name_.ptr(),
scope_name.length(),
scope_name.ptr());
} else {
ret = OB_ERR_COLUMN_DUPLICATE;
LOG_USER_ERROR(OB_ERR_COLUMN_DUPLICATE,
select_stmt.get_select_item(i).alias_name_.length(),
select_stmt.get_select_item(i).alias_name_.ptr());
}
break;
}
}
}
}
// mark all need_check_dup_name_ if neccessary
for (int64_t i = 0; OB_SUCC(ret) && i < select_stmt.get_select_item_size(); i++) {
if (select_stmt.get_select_item(i).is_real_alias_ ||
0 == select_stmt.get_select_item(i).paramed_alias_name_.length() ||
select_stmt.get_select_item(i).need_check_dup_name_) {
// do nothing
} else {
for (int64_t j = i + 1; OB_SUCC(ret) && j < select_stmt.get_select_item_size(); j++) {
if (select_stmt.get_select_item(i).is_real_alias_ ||
0 == select_stmt.get_select_item(i).paramed_alias_name_.length() ||
select_stmt.get_select_item(j).need_check_dup_name_) {
// do nothing
} else if (ObCharset::case_compat_mode_equal(select_stmt.get_select_item(i).paramed_alias_name_,
select_stmt.get_select_item(j).paramed_alias_name_)) {
select_stmt.get_select_item(i).need_check_dup_name_ = true;
select_stmt.get_select_item(j).need_check_dup_name_ = true;
}
}
}
}
return ret;
}
void ObResolverUtils::escape_char_for_oracle_mode(ObString& str)
{
if (str.length() == 2 && '\\' == str[0]) {
int with_back_slash = 0;
unsigned char escpaed_char = escaped_char(str[1], &with_back_slash);
if (1 != with_back_slash) {
str.ptr()[0] = static_cast<char>(escpaed_char);
str.assign_ptr(str.ptr(), 1);
}
}
}
} // namespace sql
} // namespace oceanbase