* 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
5245 lines
212 KiB
C++
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
|