Files
oceanbase/src/sql/resolver/ddl/ob_ddl_resolver.cpp
2021-09-14 15:33:23 +08:00

8193 lines
359 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 "lib/compress/ob_compressor_pool.h"
#include "sql/resolver/ddl/ob_ddl_resolver.h"
#include "common/sql_mode/ob_sql_mode_utils.h"
#include "common/ob_store_format.h"
#include "lib/charset/ob_charset.h"
#include "lib/string/ob_sql_string.h"
#include "share/schema/ob_table_schema.h"
#include "share/schema/ob_part_mgr_util.h"
#include "sql/resolver/ddl/ob_create_table_stmt.h"
#include "sql/resolver/ddl/ob_alter_table_stmt.h"
#include "sql/resolver/ddl/ob_create_tablegroup_stmt.h"
#include "sql/code_generator/ob_expr_generator_impl.h"
#include "sql/code_generator/ob_code_generator_impl.h"
#include "sql/session/ob_sql_session_info.h"
#include "sql/ob_sql_utils.h"
#include "sql/resolver/expr/ob_raw_expr_util.h"
#include "sql/resolver/expr/ob_raw_expr_resolver_impl.h"
#include "sql/resolver/ob_resolver_utils.h"
#include "sql/resolver/expr/ob_raw_expr_printer.h"
#include "sql/resolver/expr/ob_raw_expr_part_func_checker.h"
#include "share/ob_index_builder_util.h"
#include "share/object/ob_obj_cast.h"
#include "observer/omt/ob_tenant_config_mgr.h"
namespace oceanbase {
using namespace common;
using namespace share::schema;
using namespace share;
using namespace obrpc;
namespace sql {
ObDDLResolver::ObDDLResolver(ObResolverParams& params)
: ObStmtResolver(params),
block_size_(OB_DEFAULT_SSTABLE_BLOCK_SIZE),
consistency_level_(INVALID_CONSISTENCY),
index_scope_(NOT_SPECIFIED),
replica_num_(0),
tablet_size_(-1),
pctfree_(OB_DEFAULT_PCTFREE),
tablegroup_id_(OB_INVALID_ID),
index_attributes_set_(OB_DEFAULT_INDEX_ATTRIBUTES_SET),
charset_type_(CHARSET_INVALID),
collation_type_(CS_TYPE_INVALID),
use_bloom_filter_(false),
expire_info_(),
compress_method_(),
comment_(),
tablegroup_name_(),
primary_zone_(),
row_store_type_(MAX_ROW_STORE),
store_format_(OB_STORE_FORMAT_INVALID),
progressive_merge_num_(OB_DEFAULT_PROGRESSIVE_MERGE_NUM),
storage_format_version_(OB_STORAGE_FORMAT_VERSION_INVALID),
table_id_(OB_INVALID_ID),
data_table_id_(OB_INVALID_ID),
index_table_id_(OB_INVALID_ID),
virtual_column_id_(OB_INVALID_ID),
read_only_(false),
with_rowid_(false),
table_name_(),
database_name_(),
partition_func_type_(PARTITION_FUNC_TYPE_HASH),
auto_increment_(1),
index_name_(),
index_keyname_(NORMAL_KEY),
global_(true),
store_column_names_(),
hidden_store_column_names_(),
zone_list_(),
sort_column_array_(),
storing_column_set_(),
has_index_using_type_(false),
index_using_type_(share::schema::USING_BTREE),
locality_(),
is_random_primary_zone_(false),
max_used_part_id_(OB_INVALID_ID),
duplicate_scope_(share::ObDuplicateScope::DUPLICATE_SCOPE_NONE),
enable_row_movement_(false),
table_dop_(DEFAULT_TABLE_DOP),
hash_subpart_num_(-1)
{
table_mode_.reset();
}
ObDDLResolver::~ObDDLResolver()
{}
int ObDDLResolver::get_part_str_with_type(ObPartitionFuncType part_func_type, ObString& func_str, ObSqlString& part_str)
{
int ret = OB_SUCCESS;
ObString type_str;
if (OB_FAIL(get_part_type_str(part_func_type, type_str))) {
LOG_WARN("Failed to get part type str", K(ret));
} else if (OB_FAIL(part_str.append_fmt(
"%.*s (%.*s)", type_str.length(), type_str.ptr(), func_str.length(), func_str.ptr()))) {
LOG_WARN("Failed to append part str", K(ret));
} else {
} // do nothing
return ret;
}
/**
* set default value for primary key
*/
int ObDDLResolver::get_primary_key_default_value(const ObObjType type, ObObj& default_value)
{
int ret = OB_SUCCESS;
switch (type) {
case ObTinyIntType:
case ObSmallIntType:
case ObMediumIntType:
case ObInt32Type:
case ObIntType:
case ObUTinyIntType:
case ObUSmallIntType:
case ObUMediumIntType:
case ObUInt32Type:
case ObUInt64Type:
default_value.set_int(type, 0);
break;
case ObFloatType:
case ObUFloatType:
default_value.set_float(0);
break;
case ObDoubleType:
case ObUDoubleType:
default_value.set_double(0);
break;
case ObNumberType: // set as string
case ObUNumberType:
case ObNumberFloatType:
default_value.set_varchar("0");
default_value.set_type(ObVarcharType);
break;
case ObYearType:
default_value.set_year(ObTimeConverter::ZERO_YEAR);
break;
case ObDateType:
default_value.set_date(ObTimeConverter::ZERO_DATE);
break;
case ObTimeType:
default_value.set_time(ObTimeConverter::ZERO_TIME);
break;
case ObDateTimeType:
default_value.set_datetime(ObTimeConverter::ZERO_DATETIME);
break;
case ObTimestampTZType:
case ObTimestampLTZType:
case ObTimestampNanoType:
default_value.set_otimestamp_value(type, ObOTimestampData());
break;
case ObTimestampType:
default_value.set_ext(ObActionFlag::OP_DEFAULT_NOW_FLAG);
break;
case ObCharType:
case ObVarcharType:
case ObNVarchar2Type:
case ObNCharType:
default_value.set_string(type, ObString("").ptr(), 0);
break;
case ObRawType:
default_value.set_raw(ObString("").ptr(), 0);
break;
case ObIntervalYMType:
default_value.set_interval_ym(ObIntervalYMValue());
break;
case ObIntervalDSType:
default_value.set_interval_ds(ObIntervalDSValue());
break;
default:
ret = OB_ERR_ILLEGAL_TYPE;
SQL_RESV_LOG(WARN, "invalid type of default value", K(type), K(ret));
break;
}
return ret;
}
int update_datetime_default_value(
ObObjParam& default_value, ParseNode& def_val, const ObObjType datetime_type, const int64_t action_flag)
{
int ret = OB_SUCCESS;
int16_t scale = 0;
default_value.set_ext(action_flag);
default_value.set_param_meta();
if (def_val.value_ < 0) {
scale = ObAccuracy::DDL_DEFAULT_ACCURACY[datetime_type].get_scale();
default_value.set_scale(scale);
} else if (OB_ISNULL(def_val.children_) || OB_UNLIKELY(1 != def_val.num_child_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret), K(def_val.children_), K(def_val.num_child_));
} else {
if (NULL != def_val.children_[0]) {
scale = static_cast<int16_t>(def_val.children_[0]->value_);
} else if (lib::is_oracle_mode()) {
scale = ObAccuracy::DDL_DEFAULT_ACCURACY[datetime_type].get_scale();
} else {
scale = 0;
}
default_value.set_scale(scale);
}
return ret;
}
int ObDDLResolver::resolve_default_value(ParseNode* def_node,
// const ObObjType column_data_type,
ObObjParam& default_value)
{
int ret = OB_SUCCESS;
ObString tmp_str;
ObString str;
ObObj val;
int16_t scale = -1;
ObIAllocator* name_pool = NULL;
ParseNode* def_val = NULL;
if (NULL != def_node) {
def_val = def_node;
if (def_node->type_ == T_CONSTR_DEFAULT || (def_node->type_ == T_CONSTR_ORIG_DEFAULT)) {
def_val = def_node->children_[0];
}
if (OB_ISNULL(allocator_) || OB_ISNULL(def_val)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "allocator_ or def_val is null", K(allocator_), K(ret));
} else {
name_pool = static_cast<ObIAllocator*>(allocator_);
if (OB_ISNULL(name_pool)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "name pool is null", K(name_pool), K(ret));
}
}
if (OB_FAIL(ret)) {
// do nothing;
} else {
switch (def_val->type_) {
case T_INT:
default_value.set_int(def_val->value_);
default_value.set_param_meta();
break;
case T_UINT64:
default_value.set_uint64(static_cast<uint64_t>(def_val->value_));
default_value.set_param_meta();
break;
case T_CHAR:
case T_VARCHAR:
case T_LOB:
tmp_str.assign_ptr(const_cast<char*>(def_val->str_value_), static_cast<int32_t>(def_val->str_len_));
if ((OB_FAIL(ob_write_string(*name_pool, tmp_str, str)))) {
SQL_RESV_LOG(WARN, "Can not malloc space for default value", K(ret));
break;
}
default_value.set_varchar(str);
default_value.set_collation_type(session_info_->get_local_collation_connection());
default_value.set_param_meta();
break;
case T_RAW:
tmp_str.assign_ptr(const_cast<char*>(def_val->str_value_), static_cast<int32_t>(def_val->str_len_));
if ((OB_FAIL(ob_write_string(*name_pool, tmp_str, str)))) {
SQL_RESV_LOG(WARN, "Can not malloc space for default value", K(ret));
break;
}
default_value.set_raw(str);
default_value.set_param_meta();
break;
case T_HEX_STRING:
tmp_str.assign_ptr(const_cast<char*>(def_val->str_value_), static_cast<int32_t>(def_val->str_len_));
if ((OB_FAIL(ob_write_string(*name_pool, tmp_str, str)))) {
SQL_RESV_LOG(WARN, "Can not malloc space for default value", K(ret));
break;
}
default_value.set_hex_string(str);
default_value.set_scale(0);
default_value.set_param_meta();
break;
case T_YEAR:
default_value.set_year(static_cast<uint8_t>(def_val->value_));
default_value.set_scale(0);
default_value.set_param_meta();
break;
/*
* mysql5.6 supports syntax like: c1 date|time|timestamp default date|time|timestamp'xxx'
*/
case T_DATE: {
ObString time_str(static_cast<int32_t>(def_val->str_len_), def_val->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 {
default_value.set_date(time_val);
default_value.set_scale(0);
default_value.set_param_meta();
}
break;
}
case T_TIME: {
ObString time_str(static_cast<int32_t>(def_val->str_len_), def_val->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 {
default_value.set_time(time_val);
default_value.set_scale(scale);
default_value.set_param_meta();
}
break;
}
case T_TIMESTAMP: {
ObString time_str(static_cast<int32_t>(def_val->str_len_), def_val->str_value_);
int64_t time_val = 0;
ObTimeConvertCtx cvrt_ctx(TZ_INFO(session_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, "TIMESTAMP", to_cstring(time_str));
} else {
default_value.set_datetime(time_val);
default_value.set_scale(scale);
default_value.set_param_meta();
}
break;
}
case T_TIMESTAMP_TZ: {
ObObjType value_type = ObMaxType;
ObOTimestampData tz_value;
ObTimeConvertCtx cvrt_ctx(TZ_INFO(session_info_), false);
ObString time_str(static_cast<int32_t>(def_val->str_len_), def_val->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))) {
ret = OB_INVALID_DATE_VALUE;
LOG_USER_ERROR(OB_INVALID_DATE_VALUE, "TIMESTAMP", to_cstring(time_str));
} else {
/* use max scale bug:#18093350 */
default_value.set_otimestamp_value(value_type, tz_value);
default_value.set_scale(OB_MAX_TIMESTAMP_TZ_PRECISION);
default_value.set_param_meta();
}
break;
}
case T_DATETIME: {
ObString time_str(static_cast<int32_t>(def_val->str_len_), def_val->str_value_);
int64_t time_val = 0;
ObTimeConvertCtx cvrt_ctx(TZ_INFO(session_info_), false);
if (OB_FAIL(ObTimeConverter::literal_date_validate_oracle(time_str, cvrt_ctx, time_val))) {
ret = OB_ERR_WRONG_VALUE;
LOG_USER_ERROR(OB_ERR_WRONG_VALUE, "DATE", to_cstring(time_str));
} else {
default_value.set_datetime(time_val);
default_value.set_scale(OB_MAX_DATE_PRECISION);
default_value.set_param_meta();
}
break;
}
case T_FLOAT: {
int err = 0;
double value = 0;
char* endptr = NULL;
value = ObCharset::strntod(def_val->str_value_, static_cast<int32_t>(def_val->str_len_), &endptr, &err);
if (EOVERFLOW == err) {
ret = OB_DATA_OUT_OF_RANGE;
} else {
default_value.set_float(static_cast<float>(value));
default_value.set_param_meta();
}
break;
}
case T_DOUBLE: {
int err = 0;
double value = 0;
char* endptr = NULL;
value = ObCharset::strntod(def_val->str_value_, static_cast<int32_t>(def_val->str_len_), &endptr, &err);
if (EOVERFLOW == err) {
ret = OB_DATA_OUT_OF_RANGE;
} else {
default_value.set_double(value);
default_value.set_param_meta();
}
break;
}
case T_NUMBER:
case T_NUMBER_FLOAT: { // set as string
ObString number(static_cast<int32_t>(def_val->str_len_), def_val->str_value_);
if (OB_FAIL(ob_write_string(*name_pool, number, str))) {
SQL_RESV_LOG(WARN, "Can not malloc space for default value", K(ret));
break;
}
default_value.set_varchar(str);
default_value.set_type(ObVarcharType);
default_value.set_collation_type(ObCharset::get_system_collation());
default_value.set_param_meta();
break;
}
case T_BOOL:
default_value.set_bool(def_val->value_ == 1 ? true : false);
default_value.set_param_meta();
break;
case T_NULL:
default_value.set_type(ObNullType);
default_value.set_param_meta();
break;
case T_FUN_SYS_CUR_TIMESTAMP: {
ret = update_datetime_default_value(
default_value, *def_val, ObTimestampType, ObActionFlag::OP_DEFAULT_NOW_FLAG);
break;
}
case T_OP_POS:
ret = resolve_default_value(def_val->children_[0], default_value);
break;
case T_OP_NEG: {
ObObjParam old_obj;
ret = resolve_default_value(def_val->children_[0], old_obj);
if (OB_FAIL(ret)) {
SQL_RESV_LOG(WARN, "Resolve default const value failed", K(ret));
} else if (ObIntType == old_obj.get_type()) {
int64_t value = 0;
old_obj.get_int(value);
default_value.set_int(-value);
default_value.set_param_meta();
} else if (ObFloatType == old_obj.get_type()) {
float value = 0.0f;
if (OB_FAIL(old_obj.get_float(value))) {
SQL_RESV_LOG(WARN, "failed to get float value from old_obj", K(ret), K(old_obj));
} else {
default_value.set_float(-value);
default_value.set_param_meta();
}
} else if (ObDoubleType == old_obj.get_type()) {
double value = 0.0;
if (OB_FAIL(old_obj.get_double(value))) {
SQL_RESV_LOG(WARN, "failed to get double value", K(ret));
} else {
default_value.set_double(-value);
default_value.set_param_meta();
}
} else if (T_NUMBER == def_val->children_[0]->type_) {
ObString str;
old_obj.get_varchar(str);
char buffer[number::ObNumber::MAX_PRINTABLE_SIZE];
snprintf(buffer, sizeof(buffer), "-%.*s", str.length(), str.ptr());
if ((OB_FAIL(ob_write_string(*name_pool, ObString::make_string(buffer), str)))) {
SQL_RESV_LOG(WARN, "Can not malloc space for default value", K(ret));
break;
}
default_value.set_varchar(str);
default_value.set_collation_type(ObCharset::get_system_collation());
default_value.set_param_meta();
} else {
ret = OB_ERR_PARSER_SYNTAX;
SQL_RESV_LOG(WARN, "Invalid flag '-' in default value", K(ret));
}
break;
}
case T_INTERVAL_YM:
case T_INTERVAL_DS:
case T_NVARCHAR2:
case T_NCHAR:
case T_UROWID: {
// oracle's default value is stored as string, won't be here
ret = OB_NOT_SUPPORTED;
break;
}
default:
ret = OB_ERR_ILLEGAL_TYPE;
SQL_RESV_LOG(WARN, "Illegal type of default value", K(ret), K(def_val->type_));
break;
}
}
} else {
default_value.set_null();
default_value.set_param_meta();
}
if (OB_SUCC(ret)) {
_OB_LOG(DEBUG, "resolve default value: %s", to_cstring(default_value));
}
return ret;
}
int ObDDLResolver::set_table_name(const ObString& table_name)
{
int ret = OB_SUCCESS;
if (allocator_) {
if (OB_FAIL(ob_write_string(*allocator_, table_name, table_name_))) {
SQL_RESV_LOG(WARN, "deep copy table name failed", K(ret));
}
} else {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "allocator is null", K(ret));
}
return ret;
}
int ObDDLResolver::set_database_name(const ObString& database_name)
{
int ret = OB_SUCCESS;
if (allocator_) {
if (OB_FAIL(ob_write_string(*allocator_, database_name, database_name_))) {
SQL_RESV_LOG(WARN, "deep copy table name failed", K(ret));
}
} else {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "allocator is null", K(ret));
}
return ret;
}
int ObDDLResolver::resolve_table_id_pre(ParseNode* node)
{
int ret = OB_SUCCESS;
if (NULL != node) {
ParseNode* option_node = NULL;
int32_t num = 0;
if (T_TABLE_OPTION_LIST != node->type_ || node->num_child_ < 1) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "invalid parse node", K(ret));
} else if (OB_ISNULL(node->children_) || OB_ISNULL(session_info_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "node children or session_info_ is null", K(node->children_), K(session_info_), K(ret));
} else {
num = node->num_child_;
}
for (int64_t i = 0; OB_SUCC(ret) && i < num; ++i) {
if (OB_ISNULL(option_node = node->children_[i])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "node is null", K(ret));
} else if (option_node->type_ == T_TABLE_ID) {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
table_id_ = static_cast<uint64_t>(option_node->children_[0]->value_);
}
}
}
}
return ret;
}
int ObDDLResolver::resolve_table_options(ParseNode* node, bool is_index_option)
{
int ret = OB_SUCCESS;
if (NULL != node) {
ParseNode* option_node = NULL;
int32_t num = 0;
if (T_TABLE_OPTION_LIST != node->type_ || node->num_child_ < 1) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "invalid parse node", K(ret));
} else if (OB_ISNULL(node->children_) || OB_ISNULL(session_info_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "node children or session_info_ is null", K(node->children_), K(session_info_), K(ret));
} else {
num = node->num_child_;
}
for (int64_t i = 0; OB_SUCC(ret) && i < num; ++i) {
if (OB_ISNULL(option_node = node->children_[i])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "node is null", K(ret));
} else if (OB_FAIL(resolve_table_option(option_node, is_index_option))) {
SQL_RESV_LOG(WARN, "resolve table option failed", K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (CHARSET_INVALID == charset_type_ && CS_TYPE_INVALID == collation_type_) {
// The database character set and collation affect these aspects of server operation:
//
// For CREATE TABLE statements, the database character set and collation are used as default
// values for table definitions if the table character set and collation are not specified.
// To override this, provide explicit CHARACTER SET and COLLATE table options.
int64_t coll_cs_db_int64 = -1;
int64_t coll_db_int64 = -1;
if (OB_FAIL(session_info_->get_sys_variable(share::SYS_VAR_CHARACTER_SET_DATABASE, coll_cs_db_int64))) {
SQL_RESV_LOG(WARN, "fail to get sys variable character_set_database", K(ret));
} else if (OB_FAIL(session_info_->get_sys_variable(share::SYS_VAR_COLLATION_DATABASE, coll_db_int64))) {
SQL_RESV_LOG(WARN, "fail to get sys variable collation_database", K(ret));
} else if (!ObCharset::is_valid_collation(coll_cs_db_int64) || !ObCharset::is_valid_collation(coll_db_int64)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "invalid collation type", K(ret), K(coll_cs_db_int64), K(coll_db_int64));
} else {
charset_type_ = ObCharset::charset_type_by_coll(static_cast<ObCollationType>(coll_cs_db_int64));
collation_type_ = static_cast<ObCollationType>(coll_db_int64);
}
} else if (OB_FAIL(ObCharset::check_and_fill_info(charset_type_, collation_type_))) {
SQL_RESV_LOG(WARN, "fail to fill collation info", K(ret));
}
}
return ret;
}
/**
* @param check_column_exist is used for 'alter table add index'/'create index' to ignore schema check
* check_column_exist default is true
*/
int ObDDLResolver::add_storing_column(const ObString& column_name, bool check_column_exist, bool is_hidden)
{
int ret = OB_SUCCESS;
ObString col_name;
if (OB_ISNULL(schema_checker_) || OB_ISNULL(stmt_) || OB_ISNULL(session_info_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "schema checker or stmt cat not be null", K(ret));
}
if (OB_SUCCESS == ret && check_column_exist) {
ObColumnSchemaV2* column_schema = NULL;
if (stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
ObCreateTableStmt* create_table_stmt = static_cast<ObCreateTableStmt*>(stmt_);
ObTableSchema& tbl_schema = create_table_stmt->get_create_table_arg().schema_;
if (NULL == (column_schema = tbl_schema.get_column_schema(column_name))) {
ret = OB_ERR_BAD_FIELD_ERROR;
LOG_USER_ERROR(
OB_ERR_BAD_FIELD_ERROR, column_name.length(), column_name.ptr(), table_name_.length(), table_name_.ptr());
} else if (ob_is_text_tc(column_schema->get_data_type())) {
ret = OB_ERR_WRONG_KEY_COLUMN;
LOG_USER_ERROR(OB_ERR_WRONG_KEY_COLUMN, column_name.length(), column_name.ptr());
} else if (ObTimestampTZType == column_schema->get_data_type()) {
ret = OB_ERR_WRONG_KEY_COLUMN;
LOG_USER_ERROR(OB_ERR_WRONG_KEY_COLUMN, column_name.length(), column_name.ptr());
}
}
if (OB_SUCC(ret)) {
if (OB_ISNULL(column_schema)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "column schema is null", K(ret));
} else if (column_schema->get_rowkey_position() > 0) {
// rowkey can't be used as storing column, so ignore it
} else {
// do nothing;
}
}
}
if (OB_SUCC(ret)) {
ObColumnNameHashWrapper column_name_key(column_name);
ObColumnNameWrapper column_key(column_name, 0); // prefix length of storing column is 0
bool check_prefix_len = true;
if (is_column_exists(sort_column_array_, column_key, check_prefix_len)) {
// column exists in sort columns, so ignore it
} else if (OB_HASH_EXIST == storing_column_set_.exist_refactored(column_name_key)) {
if (is_hidden) {
// try add storing column by observer, and column is duplicate, just ignore
} else {
ret = OB_ERR_COLUMN_DUPLICATE;
LOG_USER_ERROR(OB_ERR_COLUMN_DUPLICATE, column_name.length(), column_name.ptr());
}
} else if (OB_FAIL(storing_column_set_.set_refactored(column_name_key))) {
SQL_RESV_LOG(WARN, "set column name to storing column set failed", K(ret));
} else if (!is_hidden && OB_FAIL(store_column_names_.push_back(column_name))) {
SQL_RESV_LOG(WARN, "add column name failed", K(column_name), K(ret));
} else if (is_hidden && OB_FAIL(hidden_store_column_names_.push_back(column_name))) {
SQL_RESV_LOG(WARN, "add column name failed", K(column_name), K(ret));
}
}
return ret;
}
int ObDDLResolver::add_fulltext_column(const ObString& column_name)
{
int ret = OB_SUCCESS;
ObColumnNameHashWrapper key_name(column_name);
ObColumnNameWrapper key_column_name(column_name, 0);
bool check_prefix_len = false;
if (!is_column_exists(sort_column_array_, key_column_name, check_prefix_len)) {
ret = OB_ERR_KEY_COLUMN_DOES_NOT_EXITS;
LOG_USER_ERROR(OB_ERR_KEY_COLUMN_DOES_NOT_EXITS, column_name.length(), column_name.ptr());
} else if (OB_HASH_EXIST == (ret = fulltext_column_set_.exist_refactored(key_name))) {
ret = OB_ERR_COLUMN_DUPLICATE;
LOG_USER_ERROR(OB_ERR_COLUMN_DUPLICATE, column_name.length(), column_name.ptr());
} else if (OB_HASH_NOT_EXIST != ret) {
LOG_WARN("check column name whether in fulltext columns failed", K(ret), K(column_name));
} else if (OB_FAIL(fulltext_column_set_.set_refactored(key_name))) {
LOG_WARN("set column name to fulltext column set failed", K(ret), K(column_name));
} else if (OB_FAIL(fulltext_column_names_.push_back(column_name))) {
LOG_WARN("add column name to fulltext columns failed", K(ret), K(column_name));
}
return ret;
}
int ObDDLResolver::resolve_table_option(const ParseNode* option_node, const bool is_index_option)
{
int ret = OB_SUCCESS;
const uint64_t tenant_id = session_info_->get_effective_tenant_id();
ObString database_name;
uint64_t database_id = OB_INVALID_ID;
if (OB_ISNULL(stmt_) || OB_ISNULL(allocator_) || OB_ISNULL(schema_checker_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "allocator_ or stmt_ or schema_checker_ cat not be null", K(ret));
} else {
database_name = database_name_;
}
CHECK_COMPATIBILITY_MODE(session_info_);
if (OB_FAIL(ret)) {
// do nothing
} else if (OB_FAIL(schema_checker_->get_database_id(tenant_id, database_name, database_id))) {
SQL_RESV_LOG(WARN, "fail to get database_id.", K(ret), K(database_name), K(tenant_id));
}
if (OB_SUCCESS == ret && NULL != option_node) {
switch (option_node->type_) {
case T_EXPIRE_INFO: {
// //not supported in version(1.0)
// ret = OB_NOT_SUPPORTED;
// LOG_USER_ERROR(ret, "expire info in version(1.0)");
// if (stmt::T_CREATE_INDEX == stmt_->get_stmt_type()) {
// ret = OB_ERR_PARSE_SQL;
// SQL_RESV_LOG(WARN, "Expire info can not be specified in index option", K(ret));
// }
// const bool is_index_table = false;
// if (OB_ISNULL(option_node->children_)) {
// ret = OB_ERR_UNEXPECTED;
// SQL_RESV_LOG(WARN, "(the children of option_node is null", K(option_node->children_), K(ret));
// } else if (NULL != option_node->children_[0] && T_NULL == option_node->children_[0]->type_) {
// //drop expire info
// expire_info_.assign_ptr(NULL, 0);
// } else {
// ObRawExpr *expr = NULL;
// ObString expire_info;
// expire_info.assign_ptr(const_cast<char *>(option_node->str_value_),
// static_cast<int32_t>(option_node->str_len_));
// if (OB_ISNULL(option_node->children_[0])) {
// ret = OB_ERR_UNEXPECTED;
// SQL_RESV_LOG(ERROR,"children can't be null", K(ret));
// } else if (OB_FAIL(ob_write_string(*allocator_, expire_info, expire_info_))) {
// SQL_RESV_LOG(WARN, "write string failed", K(ret));
// } else {
// if (stmt::T_ALTER_TABLE != stmt_->get_stmt_type()) {
// if (OB_FAIL(schema_checker_->get_table_schema(tenant_id, database_id, table_name_,
// is_index_table, &tab_schema))) {
// SQL_RESV_LOG(WARN, "table is not exist", K(tenant_id), K(database_id), K_(table_name),
// K(ret));
// } else if (OB_ISNULL(tab_schema)) {
// ret = OB_ERR_UNEXPECTED;
// SQL_RESV_LOG(WARN, "tab schema is null", K(tab_schema), K(ret));
// } else if ((tab_schema->get_progressive_merge_num() > 1 || progressive_merge_num_ > 1)
// && tab_schema->get_index_tid_count() > 0) {
// ret = OB_OP_NOT_ALLOW;
// SQL_RESV_LOG(WARN, "this progressive merge num > 1 and contain index table", K(ret));
// } else if (OB_FAIL(resolve_sql_expr(*(option_node->children_[0]), expr, T_EXPIRE_SCOPE))
// || OB_FAIL(stmt_->get_condition_exprs().push_back(expr))) {
// if (OB_ERR_BAD_FIELD_ERROR != ret) {
// SQL_RESV_LOG(WARN, "Resolve expire info failed", K(ret));
// }
// }
// } else {
// //mark alter table option
// if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::EXPIRE_INFO))) {
// SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
// }
// }
// }
// }
break;
}
case T_BLOCK_SIZE: {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
const int64_t block_size = option_node->children_[0]->value_;
if (block_size < MIN_BLOCK_SIZE || block_size > MAX_BLOCK_SIZE) {
ret = OB_ERR_INVALID_BLOCK_SIZE;
SQL_RESV_LOG(WARN, "block size should between 1024 and 1048576", K(block_size), K(ret));
} else {
block_size_ = block_size;
}
}
if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::BLOCK_SIZE))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
}
break;
}
case T_REPLICA_NUM: {
if (!is_index_option) {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
replica_num_ = static_cast<int32_t>(option_node->children_[0]->value_);
if (replica_num_ <= 0 || MAX_REPLICA_NUM < replica_num_) {
ret = OB_NOT_SUPPORTED;
SQL_RESV_LOG(WARN, "Invalid replica_num", K_(replica_num), K(ret));
}
}
if (ret == OB_SUCCESS && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::REPLICA_NUM))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("index option should not specify replica num", K(ret));
}
break;
}
case T_TABLET_SIZE: {
if (!is_index_option) {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
tablet_size_ = option_node->children_[0]->value_;
if (tablet_size_ < 0 || tablet_size_ & ((1 << 21) - 1)) {
ret = OB_INVALID_CONFIG;
SQL_RESV_LOG(WARN, "tablet_size must be a multiple of 2M", K_(tablet_size), K(ret));
}
}
if (ret == OB_SUCCESS && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::TABLET_SIZE))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("index option should not specify tablet size", K(ret));
}
break;
}
case T_PCTFREE: {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(ret), K(option_node->children_[0]));
} else {
pctfree_ = static_cast<int32_t>(option_node->children_[0]->value_);
if (pctfree_ < 0 || pctfree_ >= OB_MAX_PCTFREE) {
if (share::is_oracle_mode()) {
ret = OB_ERR_INVALID_PCTFREE_OR_PCTUSED_VALUE;
} else {
ret = OB_INVALID_CONFIG;
}
SQL_RESV_LOG(WARN, "invalid pctfree value", K(ret), K_(pctfree));
}
}
if (ret == OB_SUCCESS && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::PCTFREE))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
}
break;
}
case T_PCTUSED: {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(ret), K(option_node->children_[0]));
} else {
int64_t pctused = static_cast<int32_t>(option_node->children_[0]->value_);
if (pctused <= 0 || pctused > OB_MAX_PCTUSED) {
ret = OB_ERR_INVALID_PCTFREE_OR_PCTUSED_VALUE;
SQL_RESV_LOG(WARN, "invalid pctused value", K(ret), K(pctused));
}
}
break;
}
case T_INITRANS: {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(ret), K(option_node->children_[0]));
} else {
int64_t initrans = static_cast<int32_t>(option_node->children_[0]->value_);
if (initrans <= 0 || initrans > OB_MAX_TRANS) {
ret = OB_ERR_INVALID_INITRANS_VALUE;
SQL_RESV_LOG(WARN, "invalid initrans value", K(ret), K(initrans));
}
}
break;
}
case T_MAXTRANS: {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(ret), K(option_node->children_[0]));
} else {
int64_t maxtrans = static_cast<int32_t>(option_node->children_[0]->value_);
if (maxtrans < 0 || maxtrans > OB_MAX_TRANS) {
ret = OB_ERR_INVALID_MAXTRANS_VALUE;
SQL_RESV_LOG(WARN, "invalid initrans value", K(ret), K(maxtrans));
}
}
break;
}
case T_STORAGE_OPTIONS: {
if (0 == option_node->num_child_) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node's num child can not be 0", K(ret), K(option_node->num_child_));
}
for (int64_t i = 0; OB_SUCC(ret) && i < option_node->num_child_; ++i) {
if (OB_ISNULL(option_node->children_[i])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null!", K(ret), K(i));
} else {
// TODO: only support storage syntax
}
}
break;
}
case T_COMPRESSION: {
if (!is_index_option) {
ObString tmp_str;
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
tmp_str.assign_ptr(const_cast<char*>(option_node->children_[0]->str_value_),
static_cast<int32_t>(option_node->children_[0]->str_len_));
compress_method_ = tmp_str.trim();
}
bool is_find = false;
const char* find_compress_name = NULL;
for (int i = 0; OB_SUCC(ret) && i < ARRAYSIZEOF(common::compress_funcs) && !is_find; i++) {
if (0 == ObString::make_string(compress_funcs[i]).case_compare(compress_method_)) {
is_find = true;
find_compress_name = compress_funcs[i];
}
}
if (OB_FAIL(ret)) {
// do nothing
} else if (OB_ISNULL(find_compress_name)) {
ret = OB_INVALID_ARGUMENT;
LOG_USER_ERROR(OB_INVALID_ARGUMENT, to_cstring(compress_method_));
} else if (OB_FAIL(ob_write_string(*allocator_, find_compress_name, compress_method_))) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "write string failed", K(ret));
} else {
}
if (ret == OB_SUCCESS && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::COMPRESS_METHOD))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("index option should not specify compress method", K(ret));
}
break;
}
case T_STORE_FORMAT: {
if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_2100) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("Create table with store format option not supported in old version", K(ret));
} else if (!is_index_option) {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
store_format_ = static_cast<ObStoreFormatType>(option_node->children_[0]->value_);
if (!ObStoreFormat::is_store_format_valid(store_format_, share::is_oracle_mode())) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "Unexpected invalid store format value", K_(store_format), K(ret));
} else {
row_store_type_ = ObStoreFormat::get_row_store_type(store_format_);
}
if (OB_SUCC(ret) && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::STORE_FORMAT))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
} else if (share::is_oracle_mode()) {
const char* compress_name = ObStoreFormat::get_store_format_compress_name(store_format_);
if (OB_ISNULL(compress_name)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "Unexpected null compress_name", K_(store_format), K(ret));
} else if (OB_FAIL(
ob_write_string(*allocator_, ObString::make_string(compress_name), compress_method_))) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "write string failed", K(ret));
} else if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::COMPRESS_METHOD))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
}
}
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("index option should not specify compress format", K(ret));
}
break;
}
case T_PROGRESSIVE_MERGE_NUM: {
if (!is_index_option) {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
progressive_merge_num_ = option_node->children_[0]->value_;
}
if (OB_FAIL(ret)) {
// do nothing
} else if (progressive_merge_num_ < 0 || progressive_merge_num_ > MAX_PROGRESSIVE_MERGE_NUM) {
ret = OB_INVALID_ARGUMENT;
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "progressive_merge_num");
} else {
if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::PROGRESSIVE_MERGE_NUM))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
} else if (stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
ObCreateTableStmt* create_table_stmt = static_cast<ObCreateTableStmt*>(stmt_);
ObTableSchema& tbl_schema = create_table_stmt->get_create_table_arg().schema_;
if (!tbl_schema.is_user_table()) {
ret = OB_OP_NOT_ALLOW;
SQL_RESV_LOG(WARN, "only allow to set progressive merge num for data table", K(ret));
}
} else {
ret = OB_ERR_PARSE_SQL;
SQL_RESV_LOG(WARN, "PROGRESSIVE_MERGE_NUM can not be specified in creating index", K(ret));
}
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("index option should not specify progressive merge num", K(ret));
}
break;
}
case T_STORAGE_FORMAT_VERSION: {
if (!is_index_option) {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
storage_format_version_ = option_node->children_[0]->value_;
}
if (OB_FAIL(ret)) {
// do nothing
} else if (storage_format_version_ < OB_STORAGE_FORMAT_VERSION_V1 ||
storage_format_version_ >= OB_STORAGE_FORMAT_VERSION_MAX) {
ret = OB_INVALID_ARGUMENT;
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "invalid storage format version");
} else {
if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::STORAGE_FORMAT_VERSION))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
} else if (stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
ObCreateTableStmt* create_table_stmt = static_cast<ObCreateTableStmt*>(stmt_);
ObTableSchema& tbl_schema = create_table_stmt->get_create_table_arg().schema_;
if (!tbl_schema.is_user_table()) {
ret = OB_OP_NOT_ALLOW;
SQL_RESV_LOG(WARN, "only allow to set storage format version for data table", K(ret));
}
} else {
ret = OB_ERR_PARSE_SQL;
SQL_RESV_LOG(WARN, "STORAGE_FORMAT_VERSION can not be specified in creating index", K(ret));
}
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("index option should be be specified storage_format_version", K(ret));
}
break;
}
case T_USE_BLOOM_FILTER: {
if (!is_index_option) {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
use_bloom_filter_ = option_node->children_[0]->value_ ? true : false;
}
if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::USE_BLOOM_FILTER))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("index option should not specify use bloom filter", K(ret));
}
break;
}
case T_INDEX_SCOPE: {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
index_scope_ = option_node->children_[0]->value_ == 0 ? LOCAL_INDEX : GLOBAL_INDEX;
}
if (OB_SUCCESS == ret && GLOBAL_INDEX == index_scope_) {
if (OB_ISNULL(option_node->children_[1])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[1]), K(ret));
} else if (0 != STRNCMP("GLOBAL",
static_cast<const char*>(option_node->children_[1]->str_value_),
option_node->children_[1]->str_len_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "invalid index type!", K(ret));
}
}
if (OB_SUCCESS == ret && LOCAL_INDEX == index_scope_) {
if (OB_ISNULL(option_node->children_[1])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[1]), K(ret));
} else if (0 != STRNCMP("LOCAL",
static_cast<const char*>(option_node->children_[1]->str_value_),
option_node->children_[1]->str_len_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "invalid index type!", K(ret));
}
}
break;
}
case T_REVERSE: {
// support dummy syntax only
break;
}
case T_STORING_COLUMN_LIST: {
ParseNode* cur_node = NULL;
ObString column_name;
if (OB_ISNULL(option_node->children_[0]) || T_STORING_COLUMN_LIST != option_node->type_ ||
option_node->num_child_ < 1) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "invalid node type and node child!", K(ret));
}
for (int64_t i = 0; OB_SUCCESS == ret && i < option_node->num_child_; i++) {
if (OB_ISNULL(option_node->children_[i])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "invalid node type and node child!", K(ret));
} else {
cur_node = option_node->children_[i];
if (OB_ISNULL(cur_node)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "invalid node type and node child!", K(cur_node), K(ret));
} else {
int32_t len = static_cast<int32_t>(cur_node->str_len_);
column_name = ObString(len, len, cur_node->str_value_);
}
}
if (OB_FAIL(ret)) {
} else if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type() || stmt::T_CREATE_INDEX == stmt_->get_stmt_type()) {
bool check_column_exist = false;
if (OB_FAIL(add_storing_column(column_name, check_column_exist))) {
SQL_RESV_LOG(WARN, "Add storing column failed", K(ret), K(column_name));
}
} else {
if (OB_FAIL(add_storing_column(column_name))) {
SQL_RESV_LOG(WARN, "Add storing column failed", K(ret), K(column_name));
}
if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::TABLEGROUP_NAME))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
}
}
}
break;
}
case T_PARSER_NAME: {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("option_node child is null");
} else {
int32_t str_len = static_cast<int32_t>(option_node->children_[0]->str_len_);
parser_name_.assign_ptr(option_node->children_[0]->str_value_, str_len);
}
break;
}
case T_WITH_ROWID: {
with_rowid_ = true;
break;
}
case T_COMMENT: {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
comment_ = ObString(option_node->children_[0]->str_len_, option_node->children_[0]->str_value_);
ObCollationType client_cs_type = session_info_->get_local_collation_connection();
if (OB_FAIL(ObSQLUtils::copy_and_convert_string_charset(
*allocator_, comment_, comment_, client_cs_type, CS_TYPE_UTF8MB4_BIN))) {
LOG_WARN("fail to convert comment to utf8", K(ret));
}
}
if (OB_SUCC(ret)) {
if (comment_.length() > MAX_TABLE_COMMENT_LENGTH) {
comment_ = "";
if (is_index_option) {
ret = OB_ERR_TOO_LONG_INDEX_COMMENT;
LOG_USER_ERROR(OB_ERR_TOO_LONG_INDEX_COMMENT, MAX_INDEX_COMMENT_LENGTH);
} else {
ret = OB_ERR_TOO_LONG_TABLE_COMMENT;
LOG_USER_ERROR(OB_ERR_TOO_LONG_TABLE_COMMENT, MAX_TABLE_COMMENT_LENGTH);
}
}
}
if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::COMMENT))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
}
break;
}
case T_TABLEGROUP: {
if (!is_index_option) {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
tablegroup_name_.assign_ptr((char*)(option_node->children_[0]->str_value_),
static_cast<int32_t>(option_node->children_[0]->str_len_));
tablegroup_id_ = OB_INVALID_ID;
}
if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::TABLEGROUP_NAME))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("index option should not specify tablegrouop", K(ret));
}
break;
}
case T_TABLE_MODE: {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
bool is_sync_ddl_user = false;
ObString table_mode_str(static_cast<int32_t>(option_node->children_[0]->str_len_),
(char*)(option_node->children_[0]->str_value_));
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 (is_sync_ddl_user) { // in backup mode
if (OB_FAIL(ObBackUpTableModeOp::get_table_mode(table_mode_str, table_mode_))) {
LOG_WARN("Failed to get table mode from string", K(ret), K(table_mode_str));
}
} else if (0 == table_mode_str.case_compare("normal")) {
table_mode_.mode_flag_ = TABLE_MODE_NORMAL;
} else {
ret = OB_ERR_PARSER_SYNTAX;
}
if (OB_FAIL(ret)) {
SQL_RESV_LOG(WARN, "failed to resolve table mode str!", K(ret));
}
}
if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::TABLE_MODE))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
} else {
ObTableSchema tmp_table_schema;
if (OB_FAIL(get_table_schema_for_check(tmp_table_schema))) {
LOG_WARN("get table schema failed", K(ret));
} else if (table_mode_.mode_flag_ != TABLE_MODE_NORMAL) {
// alter table change PK_MODE not suppoted
ret = OB_NOT_SUPPORTED;
LOG_USER_ERROR(OB_NOT_SUPPORTED, "Unsupported table mode");
SQL_RESV_LOG(WARN, "Unsupported table mode", K(ret), K(table_mode_));
} else {
table_mode_.pk_mode_ = tmp_table_schema.get_table_mode_struct().pk_mode_;
}
}
}
break;
}
case T_CHARSET: {
if (!is_index_option) {
if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
ret = OB_NOT_SUPPORTED;
SQL_RESV_LOG(WARN, "Not support to alter charset", K(ret));
} else if (CHARSET_INVALID == charset_type_) {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
ObString node_value(option_node->children_[0]->str_len_, option_node->children_[0]->str_value_);
ObString charset = node_value.trim();
ObCharsetType charset_type = ObCharset::charset_type(charset);
if (CHARSET_INVALID == charset_type) {
ret = OB_ERR_UNKNOWN_CHARSET;
LOG_USER_ERROR(OB_ERR_UNKNOWN_CHARSET, charset.length(), charset.ptr());
} else {
charset_type_ = charset_type;
}
}
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("index option should not specify charset");
}
break;
}
case T_COLLATION: {
if (!is_index_option) {
if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
ret = OB_ERR_PARSE_SQL;
SQL_RESV_LOG(WARN, "Not support to alter collation", K(ret));
} else if (CS_TYPE_INVALID == collation_type_) {
ObString node_value(option_node->str_len_, option_node->str_value_);
ObString collation = node_value.trim();
ObCollationType collation_type = ObCharset::collation_type(collation);
if (CS_TYPE_INVALID == collation_type) {
ret = OB_ERR_UNKNOWN_COLLATION;
LOG_USER_ERROR(OB_ERR_UNKNOWN_COLLATION, collation.length(), collation.ptr());
} else {
collation_type_ = collation_type;
}
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("index option should not specify collation", K(ret));
}
break;
}
case T_TABLE_ID: {
if (!is_index_option) {
if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
ret = OB_ERR_PARSE_SQL;
SQL_RESV_LOG(WARN, "Not support to alter table id", K(ret));
break;
}
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
table_id_ = static_cast<uint64_t>(option_node->children_[0]->value_);
if (is_cte_table(table_id_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("This table cann't be a cte table", K(ret));
}
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("index option should not specify table_id", K(ret));
}
break;
}
case T_DATA_TABLE_ID: {
if (is_index_option && stmt::T_CREATE_INDEX == stmt_->get_stmt_type()) {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
uint64_t table_id = static_cast<uint64_t>(option_node->children_[0]->value_);
// 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 check_sync_ddl_user", K(ret));
// } else if (!is_sync_ddl_user) {
// ret = OB_ERR_PARSE_SQL;
// LOG_WARN("Only support for sync ddl user to specify data_table_id", K(ret),
// K(session_info_->get_user_name()));
// } else {
data_table_id_ = table_id;
// }
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("only create index can specify data_table_id for restore purpose", K(ret));
}
break;
}
case T_INDEX_TABLE_ID: {
if (is_index_option && stmt::T_CREATE_INDEX == stmt_->get_stmt_type()) {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
uint64_t table_id = static_cast<uint64_t>(option_node->children_[0]->value_);
// 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 check_sync_ddl_user", K(ret));
// } else if (!is_sync_ddl_user) {
// ret = OB_ERR_PARSE_SQL;
// LOG_WARN("Only support for sync ddl user to specify index_table_id", K(ret),
// K(session_info_->get_user_name()));
// } else {
index_table_id_ = table_id;
// }
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("only create index can specify index_table_id for restore purpose", K(ret));
}
break;
}
case T_VIRTUAL_COLUMN_ID: {
if (is_index_option && stmt::T_CREATE_INDEX == stmt_->get_stmt_type()) {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option node child is null", K(option_node->children_[0]), K(ret));
} else {
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 check_sync_ddl_user", K(ret));
} else if (!is_sync_ddl_user) {
ret = OB_ERR_PARSE_SQL;
LOG_WARN("Only support for sync ddl user to specify index_table_id",
K(ret),
K(session_info_->get_user_name()));
} else {
virtual_column_id_ = static_cast<uint64_t>(option_node->children_[0]->value_);
}
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("only create index can sepcify virtual column id for restore purpose", K(ret));
}
break;
}
case T_MAX_USED_PART_ID: {
bool is_sync_ddl_user = false;
if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
ret = OB_ERR_PARSE_SQL;
SQL_RESV_LOG(WARN, "not support alter table with max_used_part_id", K(ret));
} else if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info_, is_sync_ddl_user))) {
SQL_RESV_LOG(WARN, "Failed to check sync_dll_user", K(ret));
} else if (!is_sync_ddl_user) {
ret = OB_ERR_PARSE_SQL;
SQL_RESV_LOG(WARN,
"only support for sync ddl user to create table with max_used_part_id",
K(ret),
K(session_info_->get_user_name()));
} else {
max_used_part_id_ = static_cast<int64_t>(option_node->children_[0]->value_);
}
break;
}
case T_PRIMARY_ZONE: {
if (!is_index_option) {
ObString tmp_str;
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else if (T_DEFAULT == option_node->children_[0]->type_) {
if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_2000) {
ret = OB_OP_NOT_ALLOW;
SQL_RESV_LOG(WARN, "set primary_zone DEFAULT is not allowed now", K(ret));
LOG_USER_ERROR(OB_OP_NOT_ALLOW, "set primary_zone DEFAULT");
}
} else if (T_RANDOM == option_node->children_[0]->type_) {
if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_2000) {
ret = OB_OP_NOT_ALLOW;
SQL_RESV_LOG(WARN, "set primary_zone RANDOM is not allowed now", K(ret));
LOG_USER_ERROR(OB_OP_NOT_ALLOW, "set primary_zone RANDOM");
} else {
primary_zone_.assign_ptr(
common::OB_RANDOM_PRIMARY_ZONE, static_cast<int32_t>(strlen(common::OB_RANDOM_PRIMARY_ZONE)));
}
} else {
tmp_str.assign_ptr(const_cast<char*>(option_node->children_[0]->str_value_),
static_cast<int32_t>(option_node->children_[0]->str_len_));
primary_zone_ = tmp_str.trim();
if (GET_MIN_CLUSTER_VERSION() >= CLUSTER_VERSION_2000 && primary_zone_.empty()) {
ret = OB_OP_NOT_ALLOW;
SQL_RESV_LOG(WARN, "set primary_zone empty is not allowed now", K(ret));
LOG_USER_ERROR(OB_OP_NOT_ALLOW, "set primary_zone empty");
}
}
if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
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 check_sync_ddl_user", K(ret));
} else if (is_sync_ddl_user) {
ret = OB_IGNORE_SQL_IN_RESTORE;
LOG_WARN(
"Cannot support for sync ddl user to alter primary zone", K(ret), K(session_info_->get_user_name()));
} else if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::PRIMARY_ZONE))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("index option should not specify primary zone", K(ret));
}
break;
}
case T_READ_ONLY: {
if (!is_index_option) {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "read only options can not be null", K(ret));
} else if (T_ON == option_node->children_[0]->type_) {
read_only_ = true;
} else if (T_OFF == option_node->children_[0]->type_) {
read_only_ = false;
} else {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "unknown read only options", K(ret));
}
if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(obrpc::ObAlterTableArg::READ_ONLY))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("index option should not specify read only", K(ret));
}
break;
}
case T_AUTO_INCREMENT: {
if (!is_index_option) {
// parser filters negative value
errno = 0;
int err = 0;
uint64_t auto_increment = 0;
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "read only options can not be null", K(ret));
} else {
auto_increment = ObCharset::strntoull(option_node->children_[0]->str_value_,
static_cast<int32_t>(option_node->children_[0]->str_len_),
10,
&err);
}
/* If the value read is out of the range of representable values by a long long int,
* the function returns LLONG_MAX or LLONG_MIN, and errno is set to ERANGE.
*/
if (OB_FAIL(ret)) {
// do nothing
} else if (ERANGE == err && (UINT_MAX == auto_increment || 0 == auto_increment)) {
ret = OB_DATA_OUT_OF_RANGE;
} else if (EDOM == err) {
ObString node_str(
static_cast<int32_t>(option_node->children_[0]->str_len_), option_node->children_[0]->str_value_);
ret = OB_ERR_TRUNCATED_WRONG_VALUE_FOR_FIELD;
SQL_RESV_LOG(WARN, "failed, invalid value", K(auto_increment), K(node_str), K(err), K(ret));
LOG_USER_ERROR(OB_ERR_TRUNCATED_WRONG_VALUE_FOR_FIELD, node_str.length(), node_str.ptr());
} else {
auto_increment_ = auto_increment;
}
if (OB_SUCCESS == ret && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::AUTO_INCREMENT))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("index option should not specify autoincrement id", K(ret));
}
break;
}
case T_TABLE_RENAME: {
if (!is_index_option) {
if (stmt::T_ALTER_TABLE != stmt_->get_stmt_type()) {
ret = OB_ERR_RESOLVE_SQL;
SQL_RESV_LOG(WARN, "Can't alter table name when creating table", K(ret));
} else {
ParseNode* relation_node = NULL;
ObString new_database_name;
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "read only options can not be null", K(ret));
} else {
relation_node = option_node->children_[0];
}
if (OB_FAIL(ret)) {
} else if (OB_ISNULL(relation_node)) {
ret = OB_ERR_PARSE_SQL;
SQL_RESV_LOG(WARN, "table relation node should not be null!", K(ret));
} else if (OB_FAIL(resolve_table_relation_node(relation_node, table_name_, new_database_name))) {
} else if (table_name_.empty()) {
ret = OB_WRONG_TABLE_NAME;
LOG_USER_ERROR(OB_WRONG_TABLE_NAME, table_name_.length(), table_name_.ptr());
} else if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::TABLE_NAME))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
} else if (share::is_oracle_mode()) {
ParseNode* new_db_node = relation_node->children_[0];
if (OB_ISNULL(new_db_node)) {
database_name_ = static_cast<ObAlterTableStmt*>(stmt_)->get_org_database_name();
} else {
ret = OB_ERR_ALTER_TABLE_RENAME_WITH_OPTION;
SQL_RESV_LOG(WARN, "new_db_node should be null in oracle mode", K(ret));
}
} else {
database_name_ = new_database_name;
}
}
} else {
ret = OB_NOT_SUPPORTED;
LOG_WARN("index option should not rename table", K(ret));
}
break;
}
case T_USING_BTREE: {
has_index_using_type_ = true;
index_using_type_ = USING_BTREE;
break;
}
case T_USING_HASH: {
has_index_using_type_ = true;
index_using_type_ = USING_HASH;
break;
}
case T_ENGINE: {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "engine node can not be null", K(ret));
} else {
ObString engine_name(
static_cast<int32_t>(option_node->children_[0]->str_len_), option_node->children_[0]->str_value_);
LOG_USER_WARN(OB_ERR_UNKNOWN_STORAGE_ENGINE, engine_name.length(), engine_name.ptr());
SQL_RESV_LOG(WARN, "unknown engine", K(engine_name), K(ret));
ret = OB_SUCCESS;
}
break;
}
case T_INVISIBLE: {
index_attributes_set_ |= (uint64_t)1 << ObTableSchema::INDEX_VISIBILITY;
break;
}
case T_VISIBLE: {
/*do nothing default is visible*/
index_attributes_set_ &= ~((uint64_t)1 << ObTableSchema::INDEX_VISIBILITY);
break;
}
case T_DUPLICATE_SCOPE: {
ObString duplicate_scope_str;
share::ObDuplicateScope my_duplicate_scope = share::ObDuplicateScope::DUPLICATE_SCOPE_MAX;
if (nullptr == option_node->children_ || 1 != option_node->num_child_) {
ret = common::OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid replicate scope arg", K(ret), "num_child", option_node->num_child_);
} else if (nullptr == option_node->children_[0]) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option node child is null", K(ret));
} else {
duplicate_scope_str.assign_ptr(const_cast<char*>(option_node->children_[0]->str_value_),
static_cast<int32_t>(option_node->children_[0]->str_len_));
duplicate_scope_str = duplicate_scope_str.trim();
if (OB_FAIL(
ObDuplicateScopeChecker::convert_duplicate_scope_string(duplicate_scope_str, my_duplicate_scope))) {
SQL_RESV_LOG(WARN, "fail to convert replicate scope string", K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "duplicate_scope");
} else {
duplicate_scope_ = my_duplicate_scope;
}
if (OB_SUCC(ret) && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::DUPLICATE_SCOPE))) {
LOG_WARN("fail to add member to bitset!", K(ret));
}
}
}
break;
}
case T_LOCALITY: {
if (NULL == option_node->children_ || option_node->num_child_ != 2) {
ret = common::OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid locality argument", K(ret), "num_child", option_node->num_child_);
} else if (T_DEFAULT == option_node->children_[0]->type_) {
if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_2000) {
ret = OB_OP_NOT_ALLOW;
SQL_RESV_LOG(WARN, "set locality DEFAULT is not allowed now", K(ret));
LOG_USER_ERROR(OB_OP_NOT_ALLOW, "set locality DEFAULT");
}
} else {
int64_t locality_length = option_node->children_[0]->str_len_;
const char* locality_str = option_node->children_[0]->str_value_;
common::ObString locality(locality_length, locality_str);
if (OB_UNLIKELY(locality_length > common::MAX_LOCALITY_LENGTH)) {
ret = common::OB_ERR_TOO_LONG_IDENT;
SQL_RESV_LOG(WARN, "locality length is beyond limit", K(ret), K(locality));
LOG_USER_ERROR(OB_ERR_TOO_LONG_IDENT, locality.length(), locality.ptr());
} else if (GET_MIN_CLUSTER_VERSION() >= CLUSTER_VERSION_2000 && 0 == locality_length) {
ret = OB_OP_NOT_ALLOW;
SQL_RESV_LOG(WARN, "set locality empty is not allowed now", K(ret));
LOG_USER_ERROR(OB_OP_NOT_ALLOW, "set locality empty");
} else {
locality_.assign_ptr(locality_str, static_cast<int32_t>(locality_length));
}
}
if (OB_SUCC(ret) && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
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_dll_user", K(ret));
} else if (is_sync_ddl_user) {
ret = OB_IGNORE_SQL_IN_RESTORE;
LOG_WARN("Cannot support for sync ddl user to alter locality", K(ret), K(session_info_->get_user_name()));
} else if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::LOCALITY))) {
SQL_RESV_LOG(WARN, "fail to add member to bitset!", K(ret));
} else if (nullptr == option_node->children_[1]) {
// not force alter locality
} else if (option_node->children_[1]->type_ != T_FORCE) {
ret = common::OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "invalid node", K(ret));
} else if (OB_FAIL(alter_table_bitset_.add_member(obrpc::ObAlterTableArg::FORCE_LOCALITY))) {
SQL_RESV_LOG(WARN, "fail to add force locality member to bitset", K(ret));
}
}
break;
}
case T_ENABLE_ROW_MOVEMENT: {
if (NULL == option_node->children_ || 1 != option_node->num_child_ ||
T_BOOL != option_node->children_[0]->type_) {
ret = common::OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid row movement argument", K(ret), "num_child", option_node->num_child_);
} else {
enable_row_movement_ = static_cast<bool>(option_node->children_[0]->value_);
if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::ENABLE_ROW_MOVEMENT))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
}
}
break;
}
case T_PARALLEL: {
if (OB_ISNULL(option_node->children_[0])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "option_node child is null", K(option_node->children_[0]), K(ret));
} else {
const int64_t table_dop = option_node->children_[0]->value_;
if (table_dop <= 0) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "invalid table dop", K(table_dop), K(ret));
} else {
table_dop_ = table_dop;
}
}
if (OB_SUCC(ret) && stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(alter_table_bitset_.add_member(ObAlterTableArg::TABLE_DOP))) {
SQL_RESV_LOG(WARN, "failed to add member to bitset!", K(ret));
}
}
break;
}
default: {
/* won't be here */
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "should not reach here", K(option_node->type_), K(ret));
break;
}
}
}
return ret;
}
int ObDDLResolver::resolve_column_definition_ref(
ObColumnSchemaV2& column, ParseNode* node /* column_definition_def */, bool is_resolve_for_alter_table)
{
int ret = OB_SUCCESS;
ObString name;
int32_t name_length = 0;
const char* name_ptr = nullptr;
if (OB_ISNULL(node)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid parser tree!", K(ret), K(node));
} else if (T_COLUMN_REF != node->type_ || 3 != node->num_child_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid parser tree!", K(ret), K(node->type_), K(node->num_child_));
} else {
ParseNode* db_name_node = node->children_[0];
ParseNode* table_name_node = node->children_[1];
if (is_oracle_mode()) {
if (OB_NOT_NULL(table_name_node) || OB_NOT_NULL(db_name_node)) {
ret = OB_ERR_ONLY_SIMPLE_COLUMN_NAME_ALLOWED;
LOG_WARN("only simple column names allowed here", K(ret));
}
} else {
if (NULL != db_name_node) {
ObString dbname(db_name_node->str_len_, db_name_node->str_value_);
if (0 != dbname.compare(database_name_)) {
ret = OB_WRONG_DB_NAME;
LOG_WARN("invalid database name", K(ret));
LOG_USER_ERROR(OB_WRONG_DB_NAME, dbname.length(), dbname.ptr());
}
}
if (OB_FAIL(ret)) {
} else if (NULL != table_name_node) {
ObString table_name(table_name_node->str_len_, table_name_node->str_value_);
if (0 != table_name.compare(table_name_)) {
ret = OB_WRONG_TABLE_NAME;
LOG_WARN("invalid table name", K(ret));
LOG_USER_ERROR(OB_WRONG_TABLE_NAME, table_name.length(), table_name.ptr());
}
}
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(resolve_column_name(name, node->children_[2]))) {
LOG_WARN("resolve column name failed", K(ret));
} else if (is_resolve_for_alter_table) {
AlterColumnSchema& alter_column_schema = static_cast<AlterColumnSchema&>(column);
if (OB_FAIL(alter_column_schema.set_origin_column_name(name))) {
SQL_RESV_LOG(WARN, "fail to set origin column name", K(name), K(ret));
}
} else if (OB_FAIL(column.set_column_name(name))) {
SQL_RESV_LOG(WARN, "fail to set column name", K(name), K(ret));
}
return ret;
}
int ObDDLResolver::resolve_column_name(common::ObString& col_name, ParseNode* node /* column_name */)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(node) || T_IDENT != node->type_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid parser tree", K(ret));
} else {
col_name.assign_ptr(node->str_value_, node->str_len_);
int32_t name_length = col_name.length();
const char* name_ptr = col_name.ptr();
if (name_length > OB_MAX_COLUMN_NAME_LENGTH) {
ret = OB_ERR_TOO_LONG_IDENT;
_SQL_RESV_LOG(
WARN, "identifier name '%.*s' is too long, ret=%d", static_cast<int32_t>(name_length), name_ptr, ret);
LOG_USER_ERROR(OB_ERR_TOO_LONG_IDENT, static_cast<int32_t>(name_length), name_ptr);
} else if (0 == name_length) {
ret = OB_WRONG_COLUMN_NAME;
_SQL_RESV_LOG(WARN, "identifier name '%.*s' is empty, ret=%d", static_cast<int32_t>(name_length), name_ptr, ret);
LOG_USER_ERROR(OB_WRONG_COLUMN_NAME, static_cast<int32_t>(name_length), name_ptr);
} else {
ObCollationType cs_type = CS_TYPE_INVALID;
if (share::is_oracle_mode() && 0 == col_name.case_compare(OB_HIDDEN_LOGICAL_ROWID_COLUMN_NAME)) {
ret = OB_ERR_BAD_FIELD_ERROR;
LOG_USER_ERROR(OB_ERR_BAD_FIELD_ERROR, name_length, name_ptr, table_name_.length(), table_name_.ptr());
LOG_WARN("invalid rowid column", K(ret));
} else if (OB_FAIL(session_info_->get_collation_connection(cs_type))) {
LOG_WARN("fail to get collation_connection", K(ret));
} else if (OB_FAIL(ObSQLUtils::check_column_name(cs_type, col_name))) {
SQL_RESV_LOG(WARN, "fail to check column name", K(col_name), K(ret));
}
}
}
return ret;
}
int ObDDLResolver::resolve_column_definition(ObColumnSchemaV2& column, ParseNode* node, /* column_definition */
ObColumnResolveStat& resolve_stat, bool& is_modify_column_visibility, common::ObString& pk_name,
const bool is_add_column, const bool is_modify_column, const bool is_oracle_temp_table,
const bool is_create_table_as)
{
int ret = OB_SUCCESS;
ParseNode* column_definition_ref_node = NULL;
if (T_COLUMN_DEFINITION != node->type_ || node->num_child_ < COLUMN_DEFINITION_NUM_CHILD || OB_ISNULL(allocator_) ||
OB_ISNULL(node->children_) || OB_ISNULL(node->children_[0]) || T_COLUMN_REF != node->children_[0]->type_ ||
COLUMN_DEF_NUM_CHILD != node->children_[0]->num_child_ || OB_ISNULL(session_info_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(
WARN, "invalid parse node", K(ret), K(node->type_), K(node->num_child_), K_(allocator), K_(session_info));
} else {
resolve_stat.reset();
column_definition_ref_node = node->children_[0];
ParseNode* table_node = column_definition_ref_node->children_[1];
if (is_oracle_mode() && OB_NOT_NULL(table_node)) {
ret = OB_ERR_ONLY_SIMPLE_COLUMN_NAME_ALLOWED;
LOG_WARN("only simple column names allowed here", K(ret));
} else if (OB_SUCC(resolve_column_definition_ref(column, column_definition_ref_node, false))) {
// empty
} else {
SQL_RESV_LOG(WARN, "fail to resolve column_definition_ref", K(ret));
}
}
ParseNode* type_node = NULL;
if (OB_SUCC(ret)) {
type_node = node->children_[1];
if (OB_ISNULL(type_node)) {
if (share::is_oracle_mode() &&
(is_modify_column || GEN_COLUMN_DEFINITION_NUM_CHILD == node->num_child_ || is_create_table_as)) {
// allow data_type node to be null in Oracle mode
// 1. alter table column
// 2. generated column def
// 3. create table as
if (is_create_table_as) {
// mock a dummy data_type, will override in resolve subquery phase
ObDataType data_type;
column.set_data_type(ObUInt64Type);
column.set_charset_type(CHARSET_BINARY);
column.set_collation_type(CS_TYPE_BINARY);
}
} else {
ret = OB_ERR_INVALID_DATATYPE;
LOG_WARN("type_node is invalid", K(ret));
}
} else if (OB_UNLIKELY(!ob_is_valid_obj_type(static_cast<ObObjType>(type_node->type_)))) {
ret = OB_ERR_INVALID_DATATYPE;
SQL_RESV_LOG(WARN, "type_node or stmt_ or datatype is invalid", K(ret));
}
}
if (OB_SUCC(ret) && type_node != NULL) {
ObDataType data_type;
if (OB_FAIL(ObResolverUtils::resolve_data_type(*type_node,
column.get_column_name_str(),
data_type,
(OB_NOT_NULL(session_info_) && is_oracle_mode()),
session_info_->get_session_nls_params()))) {
LOG_WARN("resolve data type failed", K(ret), K(column.get_column_name_str()));
} else if (ObExtendType == data_type.get_obj_type()) {
ret = OB_NOT_SUPPORTED;
} else {
column.set_meta_type(data_type.get_meta_type());
column.set_accuracy(data_type.get_accuracy());
column.set_charset_type(data_type.get_charset_type());
column.set_collation_type(data_type.get_collation_type());
if (data_type.is_binary_collation()) {
column.set_binary_collation(true);
column.set_collation_type(CS_TYPE_INVALID);
}
if (data_type.get_meta_type().is_integer_type() || data_type.get_meta_type().is_numeric_type()) {
column.set_zero_fill(data_type.is_zero_fill());
}
if (ob_is_nstring_type(column.get_meta_type().get_type())) {
CK(OB_NOT_NULL(session_info_));
if (OB_SUCC(ret)) {
ObCollationType coll_type = session_info_->get_nls_collation_nation();
column.set_collation_type(coll_type);
column.set_charset_type(ObCharset::charset_type_by_coll(coll_type));
}
}
if (OB_SUCC(ret) && column.is_string_type() && stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(check_and_fill_column_charset_info(column, charset_type_, collation_type_))) {
SQL_RESV_LOG(WARN, "fail to check and fill column charset info", K(ret));
} else if (data_type.get_meta_type().is_lob()) {
if (OB_FAIL(check_text_column_length_and_promote(column, table_id_))) {
SQL_RESV_LOG(WARN, "fail to check text or blob column length", K(ret), K(column));
}
} else if (OB_FAIL(check_string_column_length(column, lib::is_oracle_mode()))) {
SQL_RESV_LOG(WARN, "fail to check string column length", K(ret), K(column));
}
}
if (OB_SUCC(ret) && ObRawType == column.get_data_type() && stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(ObDDLResolver::check_raw_column_length(column))) {
SQL_RESV_LOG(WARN, "failed to check raw column length", K(ret), K(column));
}
}
if (OB_SUCC(ret) && ObURowIDType == column.get_data_type() && stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(ObDDLResolver::check_urowid_column_length(column))) {
SQL_RESV_LOG(WARN, "failed to check rowid column length", K(ret));
}
}
if (OB_SUCC(ret) && column.is_enum_or_set()) {
if (OB_FAIL(resolve_enum_or_set_column(type_node, column))) {
LOG_WARN("fail to resolve set column", K(ret), K(column));
}
}
}
}
if (OB_SUCC(ret) && GEN_COLUMN_DEFINITION_NUM_CHILD == node->num_child_) {
ParseNode* expr_node = NULL;
if (share::is_oracle_mode() && (column.get_meta_type().is_blob() || column.get_meta_type().is_clob())) {
ret = OB_ERR_INVALID_VIRTUAL_COLUMN_TYPE;
LOG_WARN("invalid use of blob/clob type with generate defnition", K(ret), K(column.get_meta_type()));
LOG_USER_ERROR(OB_NOT_SUPPORTED, "generate column with blob type");
} else if (share::is_oracle_mode() && is_create_table_as) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("generate column in create table as not support", K(ret));
LOG_USER_ERROR(OB_NOT_SUPPORTED, "generate column in create table as");
} else if (OB_ISNULL(expr_node = node->children_[3])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr_node is null");
} else {
ObString expr_str(expr_node->str_len_, expr_node->str_value_);
ObObj default_value;
default_value.set_varchar(expr_str);
default_value.set_collation_type(ObCharset::get_system_collation());
if (OB_FAIL(column.set_cur_default_value(default_value))) {
LOG_WARN("set current default value failed", K(ret));
} else if (node->children_[4] != NULL && node->children_[4]->type_ == T_STORED_COLUMN) {
column.add_column_flag(STORED_GENERATED_COLUMN_FLAG);
} else {
column.add_column_flag(VIRTUAL_GENERATED_COLUMN_FLAG);
}
}
}
if (OB_SUCC(ret)) {
ParseNode* attrs_node = node->children_[2];
if (attrs_node != NULL) {
if (OB_UNLIKELY(6 == node->num_child_)) {
if (OB_FAIL(resolve_generated_column_attribute(column, attrs_node, resolve_stat))) {
LOG_WARN("resolve generated column attribute failed", K(ret));
}
} else if (OB_FAIL(resolve_normal_column_attribute(column, attrs_node, resolve_stat, pk_name))) {
LOG_WARN("resolve normal column attribute failed", K(ret));
}
}
// specify column pos, only supported in add column syntax within MySQL Mode
if (OB_SUCC(ret) && share::is_mysql_mode()) {
ParseNode* pos_node = NULL;
if (OB_UNLIKELY(GEN_COLUMN_DEFINITION_NUM_CHILD == node->num_child_)) {
// generated column with pos_column
pos_node = node->children_[5];
} else {
// normal column with pos_column
pos_node = node->children_[3];
}
if (NULL != pos_node) {
if (!is_add_column) {
ret = OB_NOT_SUPPORTED;
SQL_RESV_LOG(WARN, "unsupport for first or before or after column", K(ret));
}
}
}
// visibility_option, Oracle mode only
if (OB_SUCC(ret) && share::is_oracle_mode()) {
ParseNode* visiblity_node = NULL;
if (OB_UNLIKELY(GEN_COLUMN_DEFINITION_NUM_CHILD == node->num_child_)) {
visiblity_node = node->children_[5];
} else {
visiblity_node = node->children_[3];
}
if (NULL != visiblity_node) {
if (is_modify_column) {
// Column visibility modifications can not be combined with any other modified column DDL option.
if (OB_UNLIKELY(GEN_COLUMN_DEFINITION_NUM_CHILD == node->num_child_)) {
visiblity_node = node->children_[5];
if (OB_NOT_NULL(node->children_[1]) || OB_NOT_NULL(node->children_[2]) || OB_NOT_NULL(node->children_[3]) ||
OB_NOT_NULL(node->children_[4])) {
ret = OB_ERR_MODIFY_COL_VISIBILITY_COMBINED_WITH_OTHER_OPTION;
SQL_RESV_LOG(WARN,
"Column visibility modifications can not be combined with any other modified column DDL option.",
K(ret));
} else {
is_modify_column_visibility = true;
}
} else {
if (OB_NOT_NULL(node->children_[1]) || OB_NOT_NULL(node->children_[2])) {
ret = OB_ERR_MODIFY_COL_VISIBILITY_COMBINED_WITH_OTHER_OPTION;
SQL_RESV_LOG(WARN,
"Column visibility modifications can not be combined with any other modified column DDL option.",
K(ret));
} else {
is_modify_column_visibility = true;
}
}
}
if (OB_SUCC(ret)) {
if (T_INVISIBLE == visiblity_node->type_) {
const ObTableSchema* table_schema = NULL;
if (is_oracle_temp_table) {
ret = OB_ERR_INVISIBLE_COL_ON_UNSUPPORTED_TABLE_TYPE;
LOG_WARN("Invisible column is not supported on temp table.", K(ret));
} else if (OB_ISNULL(schema_checker_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("schema checker ptr is null", K(ret));
} else if (is_modify_column &&
OB_FAIL(schema_checker_->get_table_schema(column.get_table_id(), table_schema))) {
LOG_WARN("get_table_schema failed", K(ret), K(column.get_table_id()));
} else if (is_modify_column && is_sys_database_id(table_schema->get_database_id())) {
// The visibility of a column from a table owned by a SYS user cannot be modified to invisible, but can be
// modified to visible
ret = OB_ERR_MODIFY_COL_VISIBILITY_BY_SYS_USER;
SQL_RESV_LOG(
WARN, "The visibility of a column from a table owned by a SYS user cannot be changed.", K(ret));
} else {
column.add_column_flag(INVISIBLE_COLUMN_FLAG);
}
} else {
// T_VISIBLE == visiblity_node->type_
column.del_column_flag(INVISIBLE_COLUMN_FLAG);
}
}
}
}
}
return ret;
}
// only use in oracle mode
int ObDDLResolver::resolve_uk_name_from_column_attribute(ParseNode* attrs_node, common::ObString& uk_name)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(attrs_node)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("attrs_node is invalid");
}
for (int64_t i = 0; OB_SUCC(ret) && i < attrs_node->num_child_; ++i) {
ParseNode* attr_node = attrs_node->children_[i];
if (T_CONSTR_UNIQUE_KEY != attr_node->type_) {
continue;
} else {
ParseNode* uk_name_node = attr_node->children_[0];
if (OB_ISNULL(uk_name_node)) {
// do nothing
} else {
uk_name.assign_ptr(uk_name_node->str_value_, static_cast<int32_t>(uk_name_node->str_len_));
}
break;
}
}
return ret;
}
int ObDDLResolver::resolve_normal_column_attribute(
ObColumnSchemaV2& column, ParseNode* attrs_node, ObColumnResolveStat& resolve_stat, ObString& pk_name)
{
int ret = OB_SUCCESS;
ObObjParam default_value;
default_value.set_null();
bool is_set_cur_default = false;
bool is_set_orig_default = false;
ObCreateTableStmt* create_table_stmt = static_cast<ObCreateTableStmt*>(stmt_);
if (OB_ISNULL(attrs_node)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("attrs_node is invalid");
}
for (int64_t i = 0; OB_SUCC(ret) && i < attrs_node->num_child_; ++i) {
ParseNode* attr_node = attrs_node->children_[i];
switch (attr_node->type_) {
case T_CONSTR_NOT_NULL:
column.set_nullable(false);
resolve_stat.is_set_not_null_ = true;
break;
case T_CONSTR_NULL:
// set non_primary_key_column to nullable
if (!resolve_stat.is_primary_key_) {
column.set_nullable(true);
}
resolve_stat.is_set_null_ = true;
break;
case T_CONSTR_PRIMARY_KEY: {
resolve_stat.is_primary_key_ = true;
// primary key should not be nullable
column.set_nullable(false);
if (ob_is_text_tc(column.get_data_type())) {
ret = OB_ERR_WRONG_KEY_COLUMN;
LOG_USER_ERROR(
OB_ERR_WRONG_KEY_COLUMN, column.get_column_name_str().length(), column.get_column_name_str().ptr());
SQL_RESV_LOG(WARN, "BLOB, TEXT column can't be primary key", K(column), K(ret));
} else if (ObTimestampTZType == column.get_data_type()) {
ret = OB_ERR_WRONG_KEY_COLUMN;
LOG_USER_ERROR(
OB_ERR_WRONG_KEY_COLUMN, column.get_column_name_str().length(), column.get_column_name_str().ptr());
SQL_RESV_LOG(WARN, "TIMESTAMP WITH TIME ZONE column can't be primary key", K(column), K(ret));
}
if (OB_FAIL(ret)) {
} else if (share::is_oracle_mode()) {
ParseNode* pk_name_node = attr_node->children_[0];
if (OB_ISNULL(pk_name_node)) {
// do nothing
} else {
pk_name.assign_ptr(pk_name_node->str_value_, static_cast<int32_t>(pk_name_node->str_len_));
}
}
break;
}
case T_CONSTR_UNIQUE_KEY: {
resolve_stat.is_unique_key_ = true;
if (ob_is_text_tc(column.get_data_type())) {
ret = OB_ERR_WRONG_KEY_COLUMN;
LOG_USER_ERROR(
OB_ERR_WRONG_KEY_COLUMN, column.get_column_name_str().length(), column.get_column_name_str().ptr());
SQL_RESV_LOG(WARN, "BLOB, TEXT column can't be unique key", K(column), K(ret));
} else if (ObTimestampTZType == column.get_data_type()) {
ret = OB_ERR_WRONG_KEY_COLUMN;
LOG_USER_ERROR(
OB_ERR_WRONG_KEY_COLUMN, column.get_column_name_str().length(), column.get_column_name_str().ptr());
SQL_RESV_LOG(WARN, "TIMESTAMP WITH TIME ZONE column can't be unique key", K(column), K(ret));
}
break;
}
case T_CONSTR_ORIG_DEFAULT:
case T_CONSTR_DEFAULT: {
if (share::is_oracle_mode()) {
resolve_stat.is_set_default_value_ = true;
ObString expr_str(attr_node->str_len_, attr_node->str_value_);
if (OB_FAIL(ObSQLUtils::copy_and_convert_string_charset(*allocator_,
expr_str,
expr_str,
session_info_->get_local_collation_connection(),
CS_TYPE_UTF8MB4_BIN))) {
LOG_WARN("fail to copy and convert string charset", K(ret));
} else {
default_value.set_varchar(expr_str);
default_value.set_collation_type(CS_TYPE_UTF8MB4_BIN);
default_value.set_param_meta();
if (T_CONSTR_ORIG_DEFAULT == attr_node->type_) {
ret = OB_NOT_SUPPORTED;
// TODO: do it next
LOG_WARN("not support set orig default now", K(ret));
} else if (OB_FAIL(column.set_cur_default_value(default_value))) {
LOG_WARN("set current default value failed", K(ret));
} else {
column.add_column_flag(DEFAULT_EXPR_V2_COLUMN_FLAG);
}
}
} else {
if (1 != attr_node->num_child_ || NULL == attr_node->children_[0]) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "resolve default value failed", K(ret));
} else if (OB_FAIL(resolve_default_value(attr_node, default_value))) {
SQL_RESV_LOG(WARN, "resolve default value failed", K(ret));
} else if (IS_DEFAULT_NOW_OBJ(default_value)) {
if ((ObDateTimeTC != column.get_data_type_class() && ObOTimestampTC != column.get_data_type_class()) ||
default_value.get_scale() != column.get_accuracy().get_scale()) {
ret = OB_INVALID_DEFAULT;
LOG_USER_ERROR(
OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
SQL_RESV_LOG(WARN, "Invalid default value", K(column), K(default_value), K(ret));
} else {
default_value.set_scale(column.get_accuracy().get_scale());
}
}
if (OB_FAIL(ret)) {
// do nothing
} else if (!default_value.is_null() && ob_is_text_tc(column.get_data_type())) {
ret = OB_INVALID_DEFAULT;
LOG_USER_ERROR(
OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
SQL_RESV_LOG(WARN, "BLOB, TEXT column can't have a default value", K(column), K(default_value), K(ret));
} else {
if (T_CONSTR_DEFAULT == attr_node->type_) {
resolve_stat.is_set_default_value_ = true;
if (is_set_cur_default) {
ret = OB_ERR_PARSER_SYNTAX;
SQL_RESV_LOG(WARN, "cannot set current default value twice", K(ret));
} else {
is_set_cur_default = true;
column.set_cur_default_value(default_value);
}
} else {
// T_CONSTR_ORIG_DEFAULT == column.get_data_type_class()
resolve_stat.is_set_orig_default_value_ = true;
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_dll_user", K(ret));
} else if (!is_sync_ddl_user || stmt::T_CREATE_TABLE != stmt_->get_stmt_type()) {
ret = OB_ERR_PARSER_SYNTAX;
SQL_RESV_LOG(WARN, "Only support for sync ddl user to specify the orig_default_value", K(ret));
} else if (is_set_orig_default) {
ret = OB_ERR_PARSER_SYNTAX;
SQL_RESV_LOG(WARN, "cannot set orig default value twice", K(ret));
} else {
is_set_orig_default = true;
column.set_orig_default_value(default_value);
}
}
}
}
LOG_DEBUG("finish resolve default value",
K(ret),
K(default_value),
K(column),
K(attr_node->num_child_),
K(attr_node->param_num_));
break;
}
case T_CONSTR_AUTO_INCREMENT:
if (ob_is_text_tc(column.get_data_type())) {
ret = OB_ERR_COLUMN_SPEC;
LOG_USER_ERROR(OB_ERR_COLUMN_SPEC, column.get_column_name_str().length(), column.get_column_name_str().ptr());
SQL_RESV_LOG(WARN, "BLOB, TEXT column can't set autoincrement", K(column), K(default_value), K(ret));
} else {
column.set_autoincrement(true);
resolve_stat.is_autoincrement_ = true;
}
break;
case T_COLUMN_ID: {
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_dll_user", K(ret));
} else if (!is_sync_ddl_user && !GCONF.enable_sys_table_ddl) {
ret = OB_ERR_PARSE_SQL;
LOG_WARN("Only support for sync ddl user or inner_table add column to specify column id",
K(ret),
K(session_info_->get_user_name()));
} else if (attr_node->num_child_ != 1 || OB_ISNULL(attr_node->children_[0]) ||
T_INT != attr_node->children_[0]->type_) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "invalid node", K(attr_node->children_[0]), K(ret));
} else {
const uint64_t column_id = static_cast<uint64_t>(attr_node->children_[0]->value_);
// 1. column id must start with 16
// 2. shadow column for uniq index must start with 32768(32767+1)
if (column_id < OB_APP_MIN_COLUMN_ID || column_id > OB_MIN_SHADOW_COLUMN_ID) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid column id", K(column_id), K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "column id");
} else {
column.set_column_id(column_id);
}
}
break;
}
case T_COMMENT: {
if (attr_node->num_child_ != 1 || OB_ISNULL(attr_node->children_[0]) ||
T_VARCHAR != attr_node->children_[0]->type_) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "invalid node!", K(ret));
} else {
ObString comment(attr_node->children_[0]->str_len_, attr_node->children_[0]->str_value_);
ObCollationType client_cs_type = session_info_->get_local_collation_connection();
if (OB_FAIL(ObSQLUtils::copy_and_convert_string_charset(
*allocator_, comment, comment, client_cs_type, CS_TYPE_UTF8MB4_BIN))) {
LOG_WARN("fail to convert comment to utf8", K(ret), K(comment));
} else if (comment.length() >= MAX_COLUMN_COMMENT_LENGTH) {
ret = OB_ERR_TOO_LONG_FIELD_COMMENT;
LOG_USER_ERROR(OB_ERR_TOO_LONG_FIELD_COMMENT, MAX_COLUMN_COMMENT_LENGTH);
} else {
column.set_comment(comment);
}
}
break;
}
case T_ON_UPDATE:
if (ObDateTimeType == column.get_data_type() || ObTimestampType == column.get_data_type()) {
if (T_FUN_SYS_CUR_TIMESTAMP != attr_node->children_[0]->type_) {
ret = OB_ERR_PARSER_SYNTAX;
SQL_RESV_LOG(WARN,
"on_update attribute can only be timestamp or synonyms type",
"node_type",
attr_node->children_[0]->type_,
K(column),
K(ret));
} else {
int16_t scale = 0;
if (OB_UNLIKELY(NULL == attr_node->children_[0] || 1 != attr_node->children_[0]->num_child_)) {
ret = OB_INVALID_ON_UPDATE;
LOG_WARN("invalid argument", K(ret), K(attr_node->children_[0]));
} else {
if (NULL != attr_node->children_[0]->children_[0]) {
scale = static_cast<int16_t>(attr_node->children_[0]->children_[0]->value_);
} else {
// defaule value
}
if (column.get_accuracy().get_scale() != scale) {
ret = OB_INVALID_ON_UPDATE;
LOG_USER_ERROR(OB_INVALID_ON_UPDATE, column.get_column_name());
SQL_RESV_LOG(WARN, "Invalid ON UPDATE clause for ", K(column), K(ret));
} else {
column.set_on_update_current_timestamp(true);
}
}
}
} else {
ret = OB_INVALID_ON_UPDATE;
LOG_USER_ERROR(OB_INVALID_ON_UPDATE, column.get_column_name());
SQL_RESV_LOG(WARN,
"only ObDateTimeType and ObTimeStampType column can have attribute"
" of on_update",
K(column),
K(ret));
}
break;
case T_CHECK_CONSTRAINT: {
if (stmt::T_CREATE_TABLE != stmt_->get_stmt_type()) {
ret = OB_NOT_SUPPORTED;
SQL_RESV_LOG(
WARN, "Adding column-level check cst while altering table not supported", K(ret), K(stmt_->stmt_type_));
LOG_USER_ERROR(OB_NOT_SUPPORTED, "Add column-level check cst while altering table");
} else {
ObSEArray<ObConstraint, 4>& csts = create_table_stmt->get_create_table_arg().constraint_list_;
if (OB_FAIL(resolve_check_constraint_node(*attr_node, csts, &column))) {
SQL_RESV_LOG(WARN, "resolve constraint failed", K(ret));
}
}
break;
}
case T_FOREIGN_KEY: {
if (stmt::T_CREATE_TABLE != stmt_->get_stmt_type()) {
ret = OB_NOT_SUPPORTED;
SQL_RESV_LOG(
WARN, "Adding a column-level fk while altering table is not supported", K(ret), K(stmt_->stmt_type_));
LOG_USER_ERROR(OB_NOT_SUPPORTED, "Adding column-level foreign key constraints while altering table");
} else {
ObCreateForeignKeyArg foreign_key_arg;
if (OB_FAIL(resolve_foreign_key_node(attr_node, foreign_key_arg, false, &column))) {
SQL_RESV_LOG(WARN, "failed to resolve foreign key node", K(ret));
} else if (OB_FAIL(create_table_stmt->get_foreign_key_arg_list().push_back(foreign_key_arg))) {
SQL_RESV_LOG(WARN, "failed to push back foreign key arg", K(ret));
}
}
break;
}
default: // won't be here
ret = OB_ERR_PARSER_SYNTAX;
SQL_RESV_LOG(WARN, "Wrong column constraint", K(ret));
break;
}
}
if (OB_SUCC(ret) && column.get_cur_default_value().is_null() && resolve_stat.is_set_default_value_ &&
(!column.is_nullable() || resolve_stat.is_primary_key_)) {
ret = OB_INVALID_DEFAULT;
LOG_USER_ERROR(OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
SQL_RESV_LOG(WARN, "Invalid default value", K(column), K(ret));
}
// can't set both null & not null attribute at the same time
// mysql did not throw error, but it is mysql's bug:
// http://bugs.mysql.com/bug.php?id=79645
if (OB_SUCC(ret) && resolve_stat.is_set_null_ && resolve_stat.is_set_not_null_) {
ret = OB_ERR_COLUMN_DEFINITION_AMBIGUOUS;
LOG_USER_ERROR(
OB_ERR_COLUMN_DEFINITION_AMBIGUOUS, column.get_column_name_str().length(), column.get_column_name_str().ptr());
}
if (OB_SUCC(ret) && column.is_autoincrement()) {
if (column.get_cur_default_value().get_type() != ObNullType) {
ret = OB_INVALID_DEFAULT;
LOG_USER_ERROR(OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
SQL_RESV_LOG(WARN, "can not set default value for auto_increment column", K(ret));
}
if (OB_SUCC(ret)) {
// for show create table
// set auto-increment column default null => still not null
column.set_nullable(false);
}
if (OB_SUCC(ret)) {
if (column.get_data_type() < ObTinyIntType || column.get_data_type() > ObUDoubleType) {
ret = OB_ERR_COLUMN_SPEC;
LOG_USER_ERROR(OB_ERR_COLUMN_SPEC, column.get_column_name_str().length(), column.get_column_name_str().ptr());
SQL_RESV_LOG(WARN, "wrong column type for auto_increment", K(ret));
}
}
}
return ret;
}
int ObDDLResolver::resolve_generated_column_attribute(
ObColumnSchemaV2& column, ParseNode* attrs_node, ObColumnResolveStat& resolve_stat)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && attrs_node && i < attrs_node->num_child_; ++i) {
ParseNode* attr_node = attrs_node->children_[i];
switch (attr_node->type_) {
case T_CONSTR_NOT_NULL:
column.set_nullable(false);
resolve_stat.is_set_not_null_ = true;
break;
case T_CONSTR_NULL:
// set non_primary_key_column to nullable
if (!resolve_stat.is_primary_key_) {
column.set_nullable(true);
}
resolve_stat.is_set_null_ = true;
break;
case T_CONSTR_PRIMARY_KEY: {
// if (column.is_stored_generated_column()) {
// resolve_stat.is_primary_key_ = true;
// primary key should not be nullable
// column.set_nullable(false);
// } else {
ret = OB_ERR_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN;
LOG_USER_ERROR(OB_ERR_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN, "Defining a generated column as primary key");
// }
break;
}
case T_CONSTR_UNIQUE_KEY: {
resolve_stat.is_unique_key_ = true;
break;
}
case T_COMMENT: {
if (attr_node->num_child_ != 1 || OB_ISNULL(attr_node->children_[0]) ||
T_VARCHAR != attr_node->children_[0]->type_) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "invalid node!", K(ret));
} else {
ObString comment(attr_node->children_[0]->str_len_, attr_node->children_[0]->str_value_);
ObCollationType client_cs_type = session_info_->get_local_collation_connection();
if (OB_FAIL(ObSQLUtils::copy_and_convert_string_charset(
*allocator_, comment, comment, client_cs_type, CS_TYPE_UTF8MB4_BIN))) {
LOG_WARN("fail to convert comment to utf8", K(ret), K(comment));
} else if (comment.length() >= MAX_COLUMN_COMMENT_LENGTH) {
ret = OB_ERR_TOO_LONG_FIELD_COMMENT;
LOG_USER_ERROR(OB_ERR_TOO_LONG_FIELD_COMMENT, MAX_COLUMN_COMMENT_LENGTH);
} else {
column.set_comment(comment);
}
}
break;
}
case T_COLUMN_ID: {
bool is_sync_ddl_user = false;
if (attr_node->num_child_ != 1 || OB_ISNULL(attr_node->children_[0]) ||
T_INT != attr_node->children_[0]->type_) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "invalid node", K(attr_node->children_[0]), K(ret));
} else if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info_, is_sync_ddl_user))) {
LOG_WARN("Failed to check sync_dll_user", K(ret));
} else if (!is_sync_ddl_user) {
ret = OB_ERR_PARSE_SQL;
LOG_WARN("Only support for sync ddl user to specify column id", K(ret), K(session_info_->get_user_name()));
} else {
const uint64_t column_id = static_cast<uint64_t>(attr_node->children_[0]->value_);
// 1. column id must start with 16
// 2. shadow column for uniq index must start with 32768(32767+1)
if (column_id < OB_APP_MIN_COLUMN_ID || column_id > OB_MIN_SHADOW_COLUMN_ID) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid column id", K(column_id), K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "column id");
} else {
column.set_column_id(column_id);
}
}
break;
}
default: // won't be here
ret = OB_ERR_PARSER_SYNTAX;
SQL_RESV_LOG(WARN, "Wrong column constraint", K(ret));
break;
}
}
// http://bugs.mysql.com/bug.php?id=79645
if (OB_SUCCESS == ret && resolve_stat.is_set_null_ && resolve_stat.is_set_not_null_) {
ret = OB_ERR_COLUMN_DEFINITION_AMBIGUOUS;
LOG_USER_ERROR(
OB_ERR_COLUMN_DEFINITION_AMBIGUOUS, column.get_column_name_str().length(), column.get_column_name_str().ptr());
}
return ret;
}
/*
int ObDDLResolver::resolve_generated_column_definition(ObColumnSchemaV2 &column,
ParseNode *node, ObColumnResolveStat &resolve_stat)
{
int ret = OB_SUCCESS;
ParseNode *name_node = NULL;
if (T_COLUMN_DEFINITION != node->type_ || node->num_child_ != 6 ||
OB_ISNULL(allocator_) || OB_ISNULL(node->children_) || OB_ISNULL(node->children_[0]) ||
T_COLUMN_REF != node->children_[0]->type_ ||
COLUMN_DEF_NUM_CHILD != node->children_[0]->num_child_){
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "invalid parse node",K(ret));
} else {
resolve_stat.reset();
name_node = node->children_[0]->children_[2];
if (OB_ISNULL(name_node)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "name node can not be null", K(ret));
} else if (OB_FAIL(resolve_column_definition_ref(column, name_node))) {
SQL_RESV_LOG(WARN, "fail to resolve column_definition_ref", K(ret));
}
}
ParseNode *type_node = NULL;
if (OB_SUCC(ret)) {
type_node = node->children_[1];
}
if (OB_SUCC(ret) && type_node != NULL) {
ObDataType data_type;
const ObLengthSemantics default_length_semantics = LS_BYTE;
if (OB_FAIL(ObResolverUtils::resolve_data_type(*type_node,
column.get_column_name_str(),
data_type,
(session_info_ != NULL && is_oracle_mode()),
default_length_semantics))) {
LOG_WARN("resolve data type failed", K(ret), K(column.get_column_name_str()));
} else if (ObExtendType == data_type.get_obj_type()) {
const ParseNode *name_node = type_node->children_[0];
CK (OB_NOT_NULL(session_info_) && OB_NOT_NULL(schema_checker_));
CK (OB_NOT_NULL(name_node));
CK (T_SP_TYPE == name_node->type_);
if (OB_SUCC(ret)) {
uint64_t udt_id = OB_INVALID_ID;
uint64_t db_id = session_info_->get_database_id();
if (NULL != name_node->children_[0]) {
OZ (schema_checker_->get_database_id(session_info_->get_effective_tenant_id(),
ObString(name_node->children_[0]->str_len_,
name_node->children_[0]->str_value_), db_id));
}
OZ (schema_checker_->get_udt_id(session_info_->get_effective_tenant_id(), db_id, OB_INVALID_ID,
ObString(name_node->children_[1]->str_len_, name_node->children_[1]->str_value_), udt_id));
if (OB_SUCC(ret)) {
data_type.set_udt_id(udt_id);
}
}
} else { }
if (OB_SUCC(ret)) {
column.set_meta_type(data_type.get_meta_type());
column.set_accuracy(data_type.get_accuracy());
column.set_charset_type(data_type.get_charset_type());
if (data_type.is_binary_collation()) {
column.set_binary_collation(true);
column.set_collation_type(CS_TYPE_INVALID);
}
if (OB_SUCC(ret) && column.is_string_type() && stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(check_and_fill_column_charset_info(column, charset_type_, collation_type_))) {
SQL_RESV_LOG(WARN, "fail to check and fill column charset info", K(ret));
} else if (data_type.get_meta_type().is_lob()) {
if (OB_FAIL(check_text_column_length_and_promote(column))) {
SQL_RESV_LOG(WARN, "fail to check text or blob column length", K(ret), K(column));
}
} else if (OB_FAIL(check_string_column_length(column, lib::is_oracle_mode()))) {
SQL_RESV_LOG(WARN, "fail to check string column length", K(ret), K(column));
}
}
if (OB_SUCC(ret) && ObRawType == column.get_data_type() && stmt::T_CREATE_TABLE == stmt_->get_stmt_type()) {
if (OB_FAIL(ObDDLResolver::check_raw_column_length(column))) {
SQL_RESV_LOG(WARN, "failed to check raw column length", K(ret), K(column));
}
}
}
}
return ret;
}
*/
int ObDDLResolver::cast_default_value(ObObj& default_value, const ObTimeZoneInfo* tz_info,
const common::ObString* nls_formats, ObIAllocator& allocator, ObColumnSchemaV2& column_schema)
{
// cast default value
int ret = OB_SUCCESS;
const int64_t CUR_TIME = 0;
bool need_cast = false;
if (default_value.is_null()) {
need_cast = false;
} else if (column_schema.get_data_type() != default_value.get_type()) {
need_cast = true;
} else if (column_schema.is_string_type() && default_value.is_string_type() &&
column_schema.get_collation_type() != default_value.get_collation_type()) {
need_cast = true;
}
if (need_cast) {
ObAccuracy res_accuracy;
const ObDataTypeCastParams dtc_params(
tz_info, nls_formats, CS_TYPE_INVALID, CS_TYPE_INVALID, CS_TYPE_UTF8MB4_GENERAL_CI);
ObCastCtx cast_ctx(&allocator,
&dtc_params,
CUR_TIME,
share::is_oracle_mode() ? CM_ORACLE_MODE : CM_COLUMN_CONVERT,
column_schema.get_collation_type(),
NULL,
&res_accuracy);
if (ob_is_enumset_tc(column_schema.get_data_type())) {
if (OB_FAIL(cast_enum_or_set_default_value(column_schema, cast_ctx, default_value))) {
LOG_WARN("fail to cast enum or set default value", K(default_value), K(column_schema), K(ret));
}
} else if (IS_DEFAULT_NOW_OBJ(default_value)) {
if (ObDateTimeTC == column_schema.get_data_type_class()) {
if (OB_FAIL(column_schema.set_cur_default_value(default_value))) {
SQL_RESV_LOG(WARN, "set current default value failed", K(ret));
}
} else {
ret = OB_INVALID_DEFAULT;
LOG_USER_ERROR(OB_INVALID_DEFAULT,
column_schema.get_column_name_str().length(),
column_schema.get_column_name_str().ptr());
}
} else {
// so cool. cast in place.
if (OB_FAIL(ObObjCaster::to_type(column_schema.get_data_type(), cast_ctx, default_value, default_value))) {
SQL_RESV_LOG(WARN,
"cast default value failed",
K(ret),
"src_type",
default_value.get_type(),
"dst_type",
column_schema.get_data_type(),
K(ret));
} else if (ObNumberTC == column_schema.get_data_type_class()) {
number::ObNumber nmb;
nmb = default_value.get_number();
if (share::is_oracle_mode()) {
const ObObj* res_obj = &default_value;
const common::ObAccuracy& accuracy = column_schema.get_accuracy();
if (OB_FAIL(common::obj_accuracy_check(
cast_ctx, accuracy, column_schema.get_collation_type(), *res_obj, default_value, res_obj))) {
SQL_RESV_LOG(WARN, "check and round number failed on oracle mode", K(ret), K(default_value), K(*res_obj));
}
} else {
if (OB_FAIL(nmb.check_and_round(column_schema.get_data_precision(), column_schema.get_data_scale()))) {
SQL_RESV_LOG(WARN, "check and round number failed", K(ret));
}
}
if (OB_SUCC(ret)) {
default_value.set_number(column_schema.get_data_type(), nmb);
}
}
if (OB_FAIL(ret)) {
ret = OB_INVALID_DEFAULT;
LOG_USER_ERROR(OB_INVALID_DEFAULT,
column_schema.get_column_name_str().length(),
column_schema.get_column_name_str().ptr());
}
}
}
return ret;
}
int ObDDLResolver::check_default_value_length(const ObObj& default_value, const ObColumnSchemaV2& column)
{
int ret = OB_SUCCESS;
int64_t strlen = -1;
if (ObStringTC == column.get_data_type_class()) {
if (CS_TYPE_INVALID == column.get_collation_type()) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "invaild default data type", K(ret));
} else {
// get characters of default value under specified charset
ObString str;
const bool is_byte_length = is_oracle_byte_length(share::is_oracle_mode(), column.get_length_semantics());
if (default_value.is_null()) {
strlen = 0;
} else if (OB_FAIL(default_value.get_varchar(str))) {
SQL_RESV_LOG(WARN, "invalid default data", K(ret), K(str), K(default_value));
} else {
strlen = is_byte_length ? str.length()
: ObCharset::strlen_char(column.get_collation_type(), str.ptr(), str.length());
}
if (OB_SUCC(ret) && strlen > column.get_data_length()) {
ret = OB_INVALID_DEFAULT;
SQL_RESV_LOG(WARN,
"Invalid default value: length is larger than data length",
"default_value",
str,
"length",
strlen,
"data_length",
column.get_data_length(),
K(is_byte_length));
LOG_USER_ERROR(OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
}
}
} else if (ObBitTC == column.get_data_type_class()) {
int32_t bit_len = 0;
if (default_value.is_null()) {
// do nothing
} else if (OB_FAIL(get_bit_len(default_value.get_bit(), bit_len))) {
SQL_RESV_LOG(WARN, "fail to get bit length", K(ret), K(default_value), K(bit_len));
} else if (bit_len > column.get_data_precision()) {
ret = OB_INVALID_DEFAULT;
SQL_RESV_LOG(WARN,
"default value length is larger than column length",
K(ret),
K(default_value),
K(bit_len),
K(column.get_data_precision()));
LOG_USER_ERROR(OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
} else { /*do nothing*/
}
} else { /*do nothing*/
}
return ret;
}
int ObDDLResolver::build_partition_key_info(
ObTableSchema& table_schema, const bool is_subpart, const bool is_key_implicit_v2)
{
int ret = OB_SUCCESS;
ObSEArray<ObQualifiedName, 8> qualified_names;
ObRawExpr* partition_key_expr = NULL;
if (OB_FAIL(ObResolverUtils::build_partition_key_expr(
params_, table_schema, partition_key_expr, &qualified_names, is_key_implicit_v2))) {
LOG_WARN("failed to build partition key expr!", K(ret));
} else if (OB_UNLIKELY(qualified_names.count() <= 0)) {
// no primary key, error now
ret = OB_ERR_FIELD_NOT_FOUND_PART;
LOG_WARN("Field in list of fields for partition function not found in table", K(ret));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < qualified_names.count(); ++i) {
ObQualifiedName& q_name = qualified_names.at(i);
if (is_subpart) {
if (OB_FAIL(table_schema.add_subpartition_key(q_name.col_name_))) {
LOG_WARN("Failed to add subpartition key", K(ret));
}
} else if (OB_FAIL(table_schema.add_partition_key(q_name.col_name_))) {
LOG_WARN("Failed to add partition key", K(ret));
} else {
} // do nothing
}
}
return ret;
}
int ObDDLResolver::set_partition_keys(
ObTableSchema& table_schema, ObIArray<ObString>& partition_keys, const bool is_subpart)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < partition_keys.count(); ++i) {
if (is_subpart) {
if (OB_FAIL(table_schema.add_subpartition_key(partition_keys.at(i)))) {
LOG_WARN("Failed to add subpartition key", K(ret), "key_name", partition_keys.at(i));
}
} else if (OB_FAIL(table_schema.add_partition_key(partition_keys.at(i)))) {
LOG_WARN("Failed to add partition key", K(ret), "key_name", partition_keys.at(i));
} else {
} // do nothing
}
return ret;
}
void ObDDLResolver::reset()
{
block_size_ = OB_DEFAULT_SSTABLE_BLOCK_SIZE;
consistency_level_ = INVALID_CONSISTENCY;
index_scope_ = NOT_SPECIFIED;
replica_num_ = 0;
tablet_size_ = -1;
charset_type_ = CHARSET_INVALID;
collation_type_ = CS_TYPE_INVALID;
use_bloom_filter_ = false;
expire_info_.reset();
compress_method_.reset();
parser_name_.reset();
comment_.reset();
tablegroup_name_.reset();
primary_zone_.reset();
row_store_type_ = MAX_ROW_STORE;
store_format_ = OB_STORE_FORMAT_INVALID;
progressive_merge_num_ = OB_DEFAULT_PROGRESSIVE_MERGE_NUM;
storage_format_version_ = OB_STORAGE_FORMAT_VERSION_INVALID;
table_id_ = OB_INVALID_ID;
data_table_id_ = OB_INVALID_ID;
index_table_id_ = OB_INVALID_ID;
partition_func_type_ = PARTITION_FUNC_TYPE_HASH;
auto_increment_ = 1;
index_name_.reset();
index_keyname_ = NORMAL_KEY;
global_ = true;
store_column_names_.reset();
hidden_store_column_names_.reset();
sort_column_array_.reset();
storing_column_set_.reset();
fulltext_column_names_.reset();
fulltext_column_set_.reset();
locality_.reset();
is_random_primary_zone_ = false;
max_used_part_id_ = OB_INVALID_ID;
enable_row_movement_ = false;
table_mode_.reset();
table_dop_ = DEFAULT_TABLE_DOP;
hash_subpart_num_ = -1;
}
bool ObDDLResolver::is_valid_prefix_key_type(const ObObjTypeClass column_type_class)
{
return column_type_class == ObStringTC || column_type_class == ObTextTC;
}
int ObDDLResolver::check_prefix_key(const int32_t prefix_len, const ObColumnSchemaV2& column_schema)
{
int ret = OB_SUCCESS;
if (prefix_len > 0) {
if (!is_valid_prefix_key_type(column_schema.get_data_type_class())) {
ret = OB_WRONG_SUB_KEY;
SQL_RESV_LOG(
WARN, "The used key part isn't a string", "data_type_class", column_schema.get_data_type_class(), K(ret));
} else if (column_schema.get_data_length() < prefix_len) {
ret = OB_WRONG_SUB_KEY;
LOG_USER_ERROR(OB_WRONG_SUB_KEY);
SQL_RESV_LOG(WARN, "The used length is longer than the key part", K(prefix_len), K(ret));
}
}
return ret;
}
int ObDDLResolver::check_string_column_length(const ObColumnSchemaV2& column, const bool is_oracle_mode)
{
int ret = OB_SUCCESS;
if (ObStringTC != column.get_data_type_class() || CHARSET_INVALID == column.get_charset_type() ||
CS_TYPE_INVALID == column.get_collation_type()) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "column infomation is error", K(column), K(ret));
} else if (ObCharType == column.get_data_type() || ObNCharType == column.get_data_type()) {
/* compatiable with mysql
* char & binary : 255 charaters at most
* varchar & varbinary : 65536 bytes at most
* varchar(N)&varbinary(N): N is character count, N's upper bound is defined by its charset.
* char(N)&binary(N): N is charactor count, upper limit is 255 characters.
* oralce
* char(N)&raw(N): N is byte count, upper limit is 2000 bytes
*/
const int64_t max_char_length = is_oracle_mode ? OB_MAX_ORACLE_CHAR_LENGTH_BYTE : OB_MAX_CHAR_LENGTH;
const int64_t data_len = column.get_data_length();
if (data_len < 0 || data_len > max_char_length) {
ret = OB_ERR_TOO_LONG_COLUMN_LENGTH;
LOG_WARN(
"column data length is invalid", K(ret), K(max_char_length), "real_data_length", column.get_data_length());
LOG_USER_ERROR(OB_ERR_TOO_LONG_COLUMN_LENGTH, column.get_column_name(), static_cast<int>(max_char_length));
} else if (is_oracle_mode && 0 == data_len) {
ret = OB_ERR_ZERO_LEN_COL;
LOG_WARN("column data length cannot be zero on oracle mode", K(ret), K(data_len));
}
} else if (ObVarcharType == column.get_data_type() || ObNVarchar2Type == column.get_data_type()) {
int64_t mbmaxlen = 0;
if (OB_FAIL(ObCharset::get_mbmaxlen_by_coll(column.get_collation_type(), mbmaxlen))) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "fail to get mbmaxlen", K(ret), K(column.get_collation_type()));
} else {
const int64_t data_len = column.get_data_length();
if (0 == mbmaxlen) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "mbmaxlen can not be 0", K(ret));
} else if (data_len < 0 || (is_oracle_mode ? data_len > OB_MAX_ORACLE_VARCHAR_LENGTH
: data_len * mbmaxlen > OB_MAX_VARCHAR_LENGTH)) {
ret = OB_ERR_TOO_LONG_COLUMN_LENGTH;
const uint64_t real_data_length = static_cast<uint64_t>(data_len);
LOG_WARN("column data length is invalid", K(ret), K(data_len), K(real_data_length), K(mbmaxlen));
LOG_USER_ERROR(OB_ERR_TOO_LONG_COLUMN_LENGTH,
column.get_column_name(),
static_cast<int>(is_oracle_mode ? OB_MAX_ORACLE_VARCHAR_LENGTH : OB_MAX_VARCHAR_LENGTH / mbmaxlen));
} else if (is_oracle_mode && 0 == data_len) {
ret = OB_ERR_ZERO_LEN_COL;
LOG_WARN("column data length cannot be zero on oracle mode", K(ret), K(data_len));
}
}
} else {
ret = OB_ERR_UNEXPECTED;
}
return ret;
}
// raw(N): N byte: upper bound: 2000 byte
int ObDDLResolver::check_raw_column_length(const share::schema::ObColumnSchemaV2& column)
{
int ret = OB_SUCCESS;
if (ObRawType != column.get_data_type()) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "column infomation is error", K(column), K(ret));
} else {
const int64_t data_len = column.get_data_length();
if (data_len < 0 || data_len > OB_MAX_ORACLE_RAW_SQL_COL_LENGTH) {
ret = OB_ERR_TOO_LONG_COLUMN_LENGTH;
LOG_WARN("column data length is invalid",
K(ret),
K(OB_MAX_ORACLE_RAW_SQL_COL_LENGTH),
"real_data_length",
column.get_data_length());
LOG_USER_ERROR(
OB_ERR_TOO_LONG_COLUMN_LENGTH, column.get_column_name(), static_cast<int>(OB_MAX_ORACLE_RAW_SQL_COL_LENGTH));
} else if (0 == data_len) {
ret = OB_ERR_ZERO_LEN_COL;
LOG_WARN("column data length cannot be zero on oracle mode", K(ret), K(data_len));
}
}
return ret;
}
int ObDDLResolver::check_urowid_column_length(const share::schema::ObColumnSchemaV2& column)
{
int ret = OB_SUCCESS;
if (ObURowIDType != column.get_data_type()) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "column information is error", K(ret), K(column));
} else {
const int64_t data_len = column.get_data_length();
if (data_len < 0 || data_len > OB_MAX_USER_ROW_KEY_LENGTH) {
// create table t (a urwoid(int_num));
// int_num is urowid's decoded max length. i.e primary key's max length
ret = OB_ERR_TOO_LONG_COLUMN_LENGTH;
LOG_WARN("column data length is invalid",
K(ret),
K(OB_MAX_USER_ROW_KEY_LENGTH),
"real_data_length",
column.get_data_length());
LOG_USER_ERROR(
OB_ERR_TOO_LONG_COLUMN_LENGTH, column.get_column_name(), static_cast<int>(OB_MAX_USER_ROW_KEY_LENGTH));
} else if (0 == data_len) {
ret = OB_ERR_ZERO_LEN_COL;
LOG_WARN("column data length cannot be zero on oracle mode", K(ret), K(data_len));
}
}
return ret;
}
int ObDDLResolver::check_text_length(ObCharsetType cs_type, ObCollationType co_type, const char* name, ObObjType& type,
int32_t& length, bool need_rewrite_length)
{
int ret = OB_SUCCESS;
int64_t mbmaxlen = 0;
int32_t default_length = ObAccuracy::DDL_DEFAULT_ACCURACY[type].get_length();
if (!ob_is_text_tc(type) || CHARSET_INVALID == cs_type || CS_TYPE_INVALID == co_type) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "column infomation is error", K(cs_type), K(co_type), K(ret));
} else if (OB_FAIL(ObCharset::get_mbmaxlen_by_coll(co_type, mbmaxlen))) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "fail to get mbmaxlen", K(ret), K(co_type));
} else if (0 == mbmaxlen) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(ERROR, "mbmaxlen can not be 0", K(ret), K(co_type), K(mbmaxlen));
} else if (share::is_oracle_mode() || 0 == length) {
length = default_length;
} else if (0 > length) {
ret = OB_ERR_TOO_LONG_COLUMN_LENGTH;
LOG_USER_ERROR(OB_ERR_TOO_LONG_COLUMN_LENGTH, name,
static_cast<int>(ObAccuracy::DDL_DEFAULT_ACCURACY[ObLongTextType].get_length() / mbmaxlen));
SQL_RESV_LOG(WARN, "fail to check column data length",
K(ret), K(length), K(ObAccuracy::DDL_DEFAULT_ACCURACY[ObLongTextType].get_length()), K(mbmaxlen));
} else {
// eg. text(128) will be tinytext in mysql, and text(65537) will be mediumtext
if (ObTextType == type) {
if (length * mbmaxlen > ObAccuracy::DDL_DEFAULT_ACCURACY[ObLongTextType].get_length()) {
ret = OB_ERR_TOO_LONG_COLUMN_LENGTH;
LOG_USER_ERROR(OB_ERR_TOO_LONG_COLUMN_LENGTH,
name,
static_cast<int>(ObAccuracy::DDL_DEFAULT_ACCURACY[ObLongTextType].get_length() / mbmaxlen));
SQL_RESV_LOG(WARN,
"fail to check column data length",
K(ret),
K(ObAccuracy::DDL_DEFAULT_ACCURACY[ObLongTextType].get_length()),
K(mbmaxlen));
} else {
for (int64_t i = ObTinyTextType; i <= ObLongTextType; ++i) {
default_length = ObAccuracy::DDL_DEFAULT_ACCURACY[i].get_length();
if (length * mbmaxlen <= default_length) {
type = static_cast<ObObjType>(i);
length = default_length;
break;
}
}
}
} else if (share::is_mysql_mode() && length * mbmaxlen > default_length) {
ret = OB_ERR_TOO_LONG_COLUMN_LENGTH;
LOG_USER_ERROR(OB_ERR_TOO_LONG_COLUMN_LENGTH, name, static_cast<int>(default_length / mbmaxlen));
SQL_RESV_LOG(WARN, "fail to check column data length", K(ret), K(default_length), K(length), K(mbmaxlen));
} else {
length = default_length;
}
}
if (OB_SUCC(ret) && share::is_mysql_mode() && need_rewrite_length) {
if (OB_FAIL(rewrite_text_length_mysql(type, length))) {
LOG_WARN("check_text_length_mysql fails", K(ret), K(type), K(length));
}
}
return ret;
}
// old version ObTinyTextType, ObTextType, ObMediumTextType, ObLongTextType max_length is incorrect
// correct max_legth is ObTinyTextType:255 etc.
// so when create new user table, must rewrite max column length
int ObDDLResolver::rewrite_text_length_mysql(ObObjType& type, int32_t& length)
{
int ret = OB_SUCCESS;
int32_t max_length = ObAccuracy::MAX_ACCURACY[type].get_length();
if (length < 0 || length > max_length) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("length can not be less than 0 or larger than max_length", K(ret), K(type), K(length), K(max_length));
} else if (ob_is_text_tc(type) && max_length == length) {
length = length - 1;
}
return ret;
}
// TODO texttc should care about the the defined length not the actual length
int ObDDLResolver::check_text_column_length_and_promote(ObColumnSchemaV2& column, int64_t table_id)
{
int ret = OB_SUCCESS;
bool need_check_length = true;
ObObjType type = column.get_data_type();
int32_t length = column.get_data_length();
if (OB_INVALID_ID != table_id && is_inner_table(table_id)) {
// inner table don't need to rewrite
// if table_id == OB_INVALID_ID, this is not inner_table
need_check_length = false;
}
if (OB_FAIL(check_text_length(column.get_charset_type(),
column.get_collation_type(),
column.get_column_name(),
type,
length,
need_check_length))) {
LOG_WARN("failed to check text length", K(ret), K(column));
} else {
column.set_data_type(type);
column.set_data_length(length);
}
return ret;
}
int ObDDLResolver::check_and_fill_column_charset_info(
ObColumnSchemaV2& column, const ObCharsetType table_charset_type, const ObCollationType table_collation_type)
{
int ret = OB_SUCCESS;
ObCharsetType charset_type = CHARSET_INVALID;
ObCollationType collation_type = CS_TYPE_INVALID;
;
if (CHARSET_INVALID == table_charset_type || CS_TYPE_INVALID == table_collation_type) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "invalid column charset info!", K(ret));
} else {
charset_type = column.get_charset_type();
collation_type = column.get_collation_type();
}
if (OB_FAIL(ret)) {
// empty
} else if (column.is_binary_collation() && CS_TYPE_INVALID == collation_type) {
if (CHARSET_INVALID == charset_type) {
column.set_charset_type(table_charset_type);
column.set_collation_type(ObCharset::get_bin_collation(table_charset_type));
} else {
column.set_charset_type(charset_type);
column.set_collation_type(ObCharset::get_bin_collation(charset_type));
}
} else if (CHARSET_INVALID == charset_type && CS_TYPE_INVALID == collation_type) {
column.set_charset_type(table_charset_type);
column.set_collation_type(table_collation_type);
} else if (OB_FAIL(ObCharset::check_and_fill_info(charset_type, collation_type))) {
SQL_RESV_LOG(WARN, "fail to fill charset and collation info", K(collation_type), K(ret));
} else {
column.set_charset_type(charset_type);
column.set_collation_type(collation_type);
}
return ret;
}
int ObDDLResolver::resolve_part_func(ObResolverParams& params, const ParseNode* node,
const ObPartitionFuncType partition_func_type, const ObTableSchema& table_schema,
ObIArray<ObRawExpr*>& part_func_exprs, ObIArray<ObString>& partition_keys)
{
int ret = OB_SUCCESS;
part_func_exprs.reset();
partition_keys.reset();
if (OB_ISNULL(node)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret));
} else if (T_EXPR_LIST == node->type_) {
if (node->num_child_ < 1) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Partition fun node should not less than 1", K(ret));
} else if (node->num_child_ > OB_MAX_PART_COLUMNS) {
ret = OB_ERR_TOO_MANY_PARTITION_FUNC_FIELDS;
LOG_WARN("Too may partition func fields", K(ret));
} else {
ObRawExpr* func_expr = NULL;
for (int64_t i = 0; OB_SUCC(ret) && i < node->num_child_; i++) {
func_expr = NULL;
if (OB_ISNULL(node->children_[i]) || T_EXPR_LIST == node->children_[i]->type_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null or node type error", K(ret));
} else if (OB_FAIL(ObResolverUtils::resolve_partition_expr(
params, *(node->children_[i]), table_schema, partition_func_type, func_expr, &partition_keys))) {
LOG_WARN("resolve partition expr failed", K(ret));
} else if (OB_FAIL(part_func_exprs.push_back(func_expr))) {
LOG_WARN("array push back fail", K(ret));
} else {
LOG_DEBUG("succ to resolve_part_func", KPC(func_expr));
} // do nothing
} // end of for
}
} else {
ObRawExpr* func_expr = NULL;
if (OB_FAIL(ObResolverUtils::resolve_partition_expr(
params, *node, table_schema, partition_func_type, func_expr, &partition_keys))) {
LOG_WARN("resolve partition expr failed", K(ret));
} else if (OB_FAIL(part_func_exprs.push_back(func_expr))) {
LOG_WARN("array push back fail", K(ret));
} else if (partition_keys.count() > OB_MAX_PART_COLUMNS) {
ret = OB_ERR_TOO_MANY_PARTITION_FUNC_FIELDS;
LOG_WARN("too may partition func fields", K(ret));
}
}
if (OB_SUCC(ret)) {
// check duplicate of PARTITION_FUNC_TYPE_RANGE_COLUMNS
if (OB_SUCC(ret)) {
if (partition_func_type == PARTITION_FUNC_TYPE_RANGE_COLUMNS) {
for (int64_t idx = 0; OB_SUCC(ret) && idx < partition_keys.count(); ++idx) {
const ObString& key_name = partition_keys.at(idx);
for (int64_t b_idx = 0; OB_SUCC(ret) && b_idx < idx; ++b_idx) {
if (ObCharset::case_insensitive_equal(key_name, partition_keys.at(b_idx))) {
ret = OB_ERR_SAME_NAME_PARTITION_FIELD;
LOG_USER_ERROR(OB_ERR_SAME_NAME_PARTITION_FIELD, key_name.length(), key_name.ptr());
}
}
}
}
}
}
return ret;
}
int ObDDLResolver::resolve_list_partition_elements(const ObDDLStmt* stmt, ParseNode* node, const bool is_subpartition,
const ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
ObDDLStmt::array_t& list_value_exprs, ObIArray<ObPartition>& partitions, ObIArray<ObSubPartition>& subpartitions,
int64_t max_used_part_id, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(node) || OB_ISNULL(stmt_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null or stmt is null", K(ret), K(node), K(stmt_));
} else if (!is_subpartition && max_used_part_id >= 0 && max_used_part_id < node->num_child_ - 1) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("max_used_part_id is invalid", K(ret), K(max_used_part_id), K(node->num_child_));
} else {
int64_t partition_num = node->num_child_;
ParseNode* partition_expr_list = node;
ObPartition partition;
ObSubPartition subpartition;
int64_t part_id = OB_INVALID_PARTITION_ID;
bool use_part_id = false;
bool has_empty_name = false;
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; i++) {
subpartition.reset();
partition.reset();
ParseNode* element_node = partition_expr_list->children_[i];
if (OB_ISNULL(element_node) || OB_ISNULL(element_node->children_[PARTITION_ELEMENT_NODE])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition expr list node is null", K(ret), K(element_node));
} else if ((OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]) ||
OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE])) &&
!is_oracle_mode()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition expr list node is null", K(ret), K(element_node));
} else {
ObString partition_name;
if (OB_NOT_NULL(element_node->children_[PARTITION_NAME_NODE])) {
ParseNode* partition_name_node = element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE];
partition_name.assign_ptr(
partition_name_node->str_value_, static_cast<int32_t>(partition_name_node->str_len_));
} else if (is_subpartition) {
subpartition.set_is_empty_partition_name(true);
has_empty_name = true;
} else {
partition.set_is_empty_partition_name(true);
has_empty_name = true;
}
ParseNode* expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE];
if (partition_name.length() > OB_MAX_PARTITION_NAME_LENGTH) {
ret = OB_ERR_TOO_LONG_IDENT;
} else if (T_EXPR_LIST != expr_list_node->type_ && T_DEFAULT != expr_list_node->type_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr_list_node->type_ is not T_EXPR_LIST or T_DEFAULT",
K(ret),
"expr_list_node type",
expr_list_node->type_);
} else if (use_part_id) {
// special case for backup-restore module
if (OB_ISNULL(element_node->children_[PART_ID_NODE])) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Should speicify part id for all parts", K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
}
}
// add list partition elements to table schema
if (OB_SUCC(ret)) {
part_id = OB_INVALID_PARTITION_ID;
if (is_subpartition) {
subpartition.set_part_id(ObSubPartition::TEMPLATE_PART_ID);
subpartition.set_sub_part_id(i);
if (OB_FAIL(subpartition.set_part_name(partition_name))) {
LOG_WARN("Failed to set part name", K(ret));
} else {
ret = subpartitions.push_back(subpartition);
}
} else if (OB_ISNULL(element_node->children_[PART_ID_NODE])) {
part_id = max_used_part_id >= 0 ? max_used_part_id - partition_num + 1 + i : i;
} else {
bool valid = false;
part_id = static_cast<int32_t>(element_node->children_[PART_ID_NODE]->children_[0]->value_);
if (OB_FAIL(check_partid_valid(stmt, part_id, max_used_part_id, valid))) {
LOG_WARN("part id not valid", K(ret));
} else if (!valid) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("part id not valid", K(ret));
} else if (0 == i) {
use_part_id = true;
} else if (!use_part_id) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Should speicify part id for all parts", K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
}
}
}
if (OB_SUCC(ret)) {
if (part_id < 0) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition id is invalid", K(ret), K(part_id));
} else {
partition.set_part_id(part_id);
if (OB_FAIL(partition.set_part_name(partition_name))) {
LOG_WARN("Failed to set part name", K(ret));
} else {
ret = partitions.push_back(partition);
}
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(resolve_list_partition_value_node(
*expr_list_node, partition_name, part_type, part_func_exprs, list_value_exprs, in_tablegroup))) {
LOG_WARN("failed to resolve list partition value node", K(ret));
}
}
}
}
if (OB_UNLIKELY(has_empty_name) &&
(stmt::T_CREATE_TABLE == stmt->get_stmt_type() || stmt::T_CREATE_TABLEGROUP == stmt->get_stmt_type() ||
stmt::T_CREATE_INDEX == stmt->get_stmt_type())) {
if (OB_FAIL(create_name_for_empty_partition(is_subpartition, partitions, subpartitions))) {
LOG_WARN("failed to create name for empty [sub]partitions", K(ret));
}
}
}
return ret;
}
int ObDDLResolver::resolve_range_partition_elements(const ObDDLStmt* stmt, ParseNode* node, const bool is_subpartition,
const ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
ObIArray<ObRawExpr*>& range_value_exprs, ObIArray<ObPartition>& partitions, ObIArray<ObSubPartition>& subpartitions,
int64_t max_used_part_id, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(node) || OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null or stmt is null", K(ret), K(node), K(stmt));
} else if (!is_subpartition && max_used_part_id >= 0 && max_used_part_id < node->num_child_ - 1) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("max_used_part_id is invalid", K(ret), K(max_used_part_id), K(node->num_child_));
} else {
int64_t partition_num = node->num_child_;
ParseNode* partition_expr_list = node;
ObPartition partition;
ObSubPartition subpartition;
bool init_specified = false;
bool has_empty_name = false;
// ignore alter_table with part_id
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; i++) {
subpartition.reset();
partition.reset();
ParseNode* element_node = partition_expr_list->children_[i];
if (OB_ISNULL(element_node) || OB_ISNULL(element_node->children_[PARTITION_ELEMENT_NODE])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition expr list node is null", K(ret), K(element_node));
} else if ((OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]) ||
OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE])) &&
!is_oracle_mode()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition expr list node is null", K(ret), K(element_node));
} else {
ObString partition_name;
if (OB_NOT_NULL(element_node->children_[PARTITION_NAME_NODE])) {
ParseNode* partition_name_node = element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE];
partition_name.assign_ptr(
partition_name_node->str_value_, static_cast<int32_t>(partition_name_node->str_len_));
} else if (is_subpartition) {
subpartition.set_is_empty_partition_name(true);
has_empty_name = true;
} else {
partition.set_is_empty_partition_name(true);
has_empty_name = true;
}
ParseNode* expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE];
if (partition_name.length() > OB_MAX_PARTITION_NAME_LENGTH) {
ret = OB_ERR_TOO_LONG_IDENT;
} else if (T_EXPR_LIST != expr_list_node->type_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr_list_node->type_ is not T_EXPR_LIST", K(ret));
} else if (part_func_exprs.count() != expr_list_node->num_child_) {
ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
} else {
// add range partition elements to table schema
if (OB_SUCC(ret)) {
if (is_subpartition) {
subpartition.set_part_id(ObSubPartition::TEMPLATE_PART_ID);
subpartition.set_sub_part_id(i);
if (OB_FAIL(subpartition.set_part_name(partition_name))) {
LOG_WARN("Failed to set part name", K(ret));
} else {
ret = subpartitions.push_back(subpartition);
}
} else {
int64_t part_id = OB_INVALID_ID;
bool current_spec = false;
if (OB_ISNULL(element_node->children_[PART_ID_NODE])) {
// part_id not specified
part_id = max_used_part_id >= 0 ? max_used_part_id - partition_num + 1 + i : i;
current_spec = false;
} else {
// with part_id
part_id = static_cast<int32_t>(element_node->children_[PART_ID_NODE]->children_[0]->value_);
if (OB_FAIL(check_partid_valid(stmt, part_id, max_used_part_id, current_spec))) {
LOG_WARN("part id not valid", K(ret));
} else if (!current_spec) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("part id not valid", K(ret));
}
}
// all with part id, or all without part id.
// otherwise unsupported
if (OB_SUCC(ret)) {
if (0 == i) {
init_specified = current_spec;
} else if (current_spec != init_specified) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Should speicify part id for all parts", K(ret));
LOG_USER_ERROR(
OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
}
}
if (OB_FAIL(ret)) {
} else if (part_id < 0) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid part_id", K(ret), K(part_id));
} else if (OB_FAIL(partition.set_part_name(partition_name))) {
LOG_WARN("Failed to set part name", K(ret));
} else {
partition.set_part_id(part_id);
ret = partitions.push_back(partition);
}
}
}
for (int64_t j = 0; OB_SUCC(ret) && j < expr_list_node->num_child_; j++) {
if (OB_ISNULL(expr_list_node->children_[j])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null", K(ret));
} else if (T_MAXVALUE == expr_list_node->children_[j]->type_) {
ObRawExpr* maxvalue_expr = NULL;
ObConstRawExpr* c_expr = NULL;
c_expr = (ObConstRawExpr*)allocator_->alloc(sizeof(ObConstRawExpr));
if (NULL != c_expr) {
c_expr = new (c_expr) ObConstRawExpr();
maxvalue_expr = c_expr;
maxvalue_expr->set_data_type(common::ObMaxType);
if (OB_FAIL(range_value_exprs.push_back(maxvalue_expr))) {
LOG_WARN("array push back fail", K(ret));
}
} else {
ret = OB_ALLOCATE_MEMORY_FAILED;
}
} else if (T_NULL == expr_list_node->children_[j]->type_) {
ret = OB_EER_NULL_IN_VALUES_LESS_THAN;
LOG_WARN("null value is not allowed in less than", K(ret));
} else if (T_EXPR_LIST != expr_list_node->children_[j]->type_) {
ObRawExpr* part_value_expr = NULL;
ObRawExpr* part_func_expr = NULL;
if (OB_FAIL(part_func_exprs.at(j, part_func_expr))) {
LOG_WARN("get part expr failed", K(j), "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_,
*(expr_list_node->children_[j]),
partition_name,
part_type,
*part_func_expr,
part_value_expr,
in_tablegroup))) {
LOG_WARN("resolve partition expr failed", K(ret));
} else if (OB_FAIL(range_value_exprs.push_back(part_value_expr))) {
LOG_WARN("array push back fail", K(ret));
}
} else {
ret = OB_ERR_PARSER_SYNTAX;
LOG_WARN("syntax error, expect single expr while expr list got", K(ret));
}
}
}
}
}
if (OB_UNLIKELY(has_empty_name) &&
(stmt::T_CREATE_TABLE == stmt->get_stmt_type() || stmt::T_CREATE_TABLEGROUP == stmt->get_stmt_type() ||
stmt::T_CREATE_INDEX == stmt->get_stmt_type())) {
if (OB_FAIL(create_name_for_empty_partition(is_subpartition, partitions, subpartitions))) {
LOG_WARN("failed to create name for empty [sub]partitions", K(ret));
}
}
}
return ret;
}
int ObDDLResolver::check_partid_valid(
const ObDDLStmt* stmt, const int64_t part_id, const int64_t max_used_part_id, bool& valid)
{
int ret = OB_SUCCESS;
bool is_sync_ddl_user = false;
if (OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("stmt is null", K(ret));
} else if (stmt::T_CREATE_TABLE != stmt->get_stmt_type() && stmt::T_CREATE_TABLEGROUP != stmt->get_stmt_type() &&
stmt::T_CREATE_INDEX != stmt->get_stmt_type()) {
ret = OB_ERR_PARSE_SQL;
LOG_WARN(
"only support create table or tablegroup or index with part_id", K(ret), "stmt_type", stmt->get_stmt_type());
} else if (OB_FAIL(ObResolverUtils::check_sync_ddl_user(session_info_, is_sync_ddl_user))) {
LOG_WARN("Failed to check sync_dll_user", K(ret));
} else if (!is_sync_ddl_user) {
ret = OB_ERR_PARSE_SQL;
LOG_WARN("Only support for sync ddl user to specify part id", K(ret), "user name", session_info_->get_user_name());
} else if (max_used_part_id < 0) {
// must specify max_used_part_id
ret = OB_OP_NOT_ALLOW;
LOG_WARN("specific part_id without max_used_part_id not allowed", K(max_used_part_id), K(ret));
LOG_USER_ERROR(OB_OP_NOT_ALLOW, "specify part_id without max_used_part_id");
} else if (part_id > max_used_part_id) {
// can't larger than max_used_part_id
ret = OB_INVALID_ARGUMENT;
LOG_WARN("part_id is bigger than max_used_part_id", K(part_id), K(max_used_part_id), K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "part_id or max_used_part_id");
} else {
valid = true;
}
return ret;
}
int ObDDLResolver::check_max_used_part_id_valid(
const share::schema::ObTableSchema& table_schema, int64_t& max_used_part_id)
{
int ret = OB_SUCCESS;
int64_t current_max_part_id = -1;
if (table_schema.is_auto_partitioned_table()) {
} else if (table_schema.is_range_part() || table_schema.is_list_part()) {
// get max part id
ObPartition** part_array = table_schema.get_part_array();
if (OB_FAIL(GET_PART_ID(part_array, table_schema.get_first_part_num() - 1, current_max_part_id))) {
LOG_WARN("Failed to get part id", K(table_schema.get_first_part_num() - 1), K(ret));
}
} else {
current_max_part_id = table_schema.get_part_option().get_part_num() - 1;
}
if (OB_SUCC(ret)) {
if (max_used_part_id < 0) {
max_used_part_id = current_max_part_id;
} else if (PARTITION_LEVEL_ZERO == table_schema.get_part_level()) {
ret = OB_NOT_SUPPORTED;
SQL_RESV_LOG(WARN, "non-partitioned table with max_used_part_id not support", K(ret), K(max_used_part_id));
LOG_USER_ERROR(OB_NOT_SUPPORTED, "non-partitioned table with max_used_part_id");
} else if (max_used_part_id < current_max_part_id) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid max_used_part_id", K(ret), K(max_used_part_id), K(current_max_part_id));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "max_used_part_id");
} else {
// use max_used_part_id_
}
}
return ret;
}
int ObDDLResolver::check_partition_name_duplicate(ParseNode* node, bool is_oracle_modle)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(node)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null", K(ret));
} else {
hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>* partition_name_set = nullptr;
void* buf = nullptr;
int64_t partition_num = node->num_child_;
ParseNode* partition_expr_list = node;
ParseNode* element_node = NULL;
if (OB_ISNULL(buf = allocator_->alloc(
sizeof(hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("fail to allocate memory", KR(ret));
} else {
partition_name_set =
new (buf) hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>();
}
if (OB_FAIL(ret)) {
} else if (OB_ISNULL(partition_name_set)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition name hash set is null", KR(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; i++) {
element_node = partition_expr_list->children_[i];
if (OB_ISNULL(element_node) || OB_ISNULL(element_node->children_[PARTITION_ELEMENT_NODE])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition expr list node is null", K(ret), K(element_node));
} else if ((OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]) ||
OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE])) &&
!is_oracle_modle) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition expr list node is null", K(ret), K(element_node));
} else {
ObString partition_name;
if (OB_NOT_NULL(element_node->children_[PARTITION_NAME_NODE])) {
ParseNode* partition_name_node = element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE];
partition_name.assign_ptr(
partition_name_node->str_value_, static_cast<int32_t>(partition_name_node->str_len_));
ObPartitionNameHashWrapper partition_name_key(partition_name);
if (OB_HASH_EXIST == partition_name_set->exist_refactored(partition_name_key)) {
ret = OB_ERR_SAME_NAME_PARTITION;
LOG_USER_ERROR(OB_ERR_SAME_NAME_PARTITION, partition_name.length(), partition_name.ptr());
} else {
if (OB_FAIL(partition_name_set->set_refactored(partition_name_key))) {
LOG_WARN("add partition name to map failed", K(ret), K(ret));
}
}
}
}
}
}
return ret;
}
int ObDDLResolver::fill_extended_type_info(const ParseNode& str_list_node, ObColumnSchemaV2& column)
{
int ret = OB_SUCCESS;
ObArray<ObString> type_info_array;
CK(NULL != session_info_);
CK(NULL != allocator_);
if (OB_FAIL(ret)) {
} else if (OB_FAIL(ObResolverUtils::resolve_extended_type_info(str_list_node, type_info_array))) {
LOG_WARN("failed to resolve extended type info", K(ret));
} else {
// The resolved extended type info's collation is session connection collation,
// need convert to column collation finally. The converting may be done in RS,
// but the session connection collation info is lost in RS, so we convert to a
// intermediate collation (system collation) here. Convert from the intermediate
// collation to column collation finally in ObResolverUtils::check_extended_type_info().
ObCollationType src = session_info_->get_local_collation_connection();
ObCollationType dst = ObCharset::get_system_collation();
FOREACH_CNT_X(str, type_info_array, OB_SUCC(ret))
{
OZ(ObCharset::charset_convert(*allocator_, *str, src, dst, *str));
}
}
OZ(column.set_extended_type_info(type_info_array));
return ret;
}
int ObDDLResolver::resolve_enum_or_set_column(const ParseNode* type_node, ObColumnSchemaV2& column)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(type_node) || OB_UNLIKELY(type_node->num_child_ != 4) || OB_ISNULL(allocator_) ||
OB_ISNULL(session_info_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("type node is NULL", K(ret), K(type_node), K(session_info_));
} else if (OB_ISNULL(type_node->children_[3])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("child is NULL", K(ret));
} else if (OB_FAIL(fill_extended_type_info(*(type_node->children_[3]), column))) {
LOG_WARN("fail to fill type info", K(ret), K(column));
} else if (stmt::T_ALTER_TABLE == stmt_->get_stmt_type()) {
} else if (OB_FAIL(check_and_fill_column_charset_info(column, charset_type_, collation_type_))) {
LOG_WARN("fail to check and fill column charset info", K(ret), K(column), K(charset_type_), K(collation_type_));
} else if (OB_FAIL(check_extended_type_info(column, session_info_->get_sql_mode()))) {
LOG_WARN("fail to fill extended type info", K(ret), K(column), K(session_info_->get_sql_mode()));
} else if (OB_FAIL(calc_enum_or_set_data_length(column))) {
LOG_WARN("fail to calc data length", K(ret), K(column));
}
return ret;
}
int ObDDLResolver::calc_enum_or_set_data_length(const ObIArray<common::ObString>& type_info,
const ObCollationType& collation_type, const ObObjType& type, int32_t& length)
{
int ret = OB_SUCCESS;
int32_t cur_len = 0;
if (OB_UNLIKELY(ObEnumType != type && ObSetType != type)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected column type", K(ret));
} else if (ObEnumType == type) {
for (int64_t i = 0; OB_SUCC(ret) && i < type_info.count(); ++i) {
const ObString& type_str = type_info.at(i);
cur_len = static_cast<int32_t>(ObCharset::strlen_char(collation_type, type_str.ptr(), type_str.length()));
length = length < cur_len ? cur_len : length;
}
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < type_info.count(); ++i) {
const ObString& type_str = type_info.at(i);
cur_len = static_cast<int32_t>(ObCharset::strlen_char(collation_type, type_str.ptr(), type_str.length()));
length += cur_len;
}
length +=
(static_cast<int32_t>(type_info.count()) - 1) * ObCharsetUtils::get_const_str(collation_type, ',').length();
}
return ret;
}
int ObDDLResolver::calc_enum_or_set_data_length(ObColumnSchemaV2& column)
{
int ret = OB_SUCCESS;
int32_t length = 0;
if (OB_FAIL(calc_enum_or_set_data_length(
column.get_extended_type_info(), column.get_collation_type(), column.get_data_type(), length))) {
LOG_WARN("failed to calc enum or set data length", K(ret));
} else {
column.set_data_length(length);
}
return ret;
}
int ObDDLResolver::check_extended_type_info(ObColumnSchemaV2& column, ObSQLMode sql_mode)
{
return ObResolverUtils::check_extended_type_info(*allocator_,
column.get_extended_type_info(),
ObCharset::get_system_collation(),
column.get_column_name_str(),
column.get_data_type(),
column.get_collation_type(),
sql_mode);
}
int ObDDLResolver::check_duplicates_in_type_infos(const ObColumnSchemaV2& col, ObSQLMode sql_mode, int32_t& dup_cnt)
{
return ObResolverUtils::check_duplicates_in_type_infos(col.get_extended_type_info(),
col.get_column_name_str(),
col.get_data_type(),
col.get_collation_type(),
sql_mode,
dup_cnt);
}
int ObDDLResolver::check_type_info_incremental_change(
const ObColumnSchemaV2& ori_schema, const ObColumnSchemaV2& new_schema)
{
int ret = OB_SUCCESS;
const ObIArray<common::ObString>& ori_type_info = ori_schema.get_extended_type_info();
const ObIArray<common::ObString>& new_type_info = new_schema.get_extended_type_info();
if (OB_UNLIKELY(new_type_info.count() < ori_type_info.count())) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(new_type_info.count()), K(ori_type_info.count()), K(ret));
} else if (OB_UNLIKELY(ori_schema.get_charset_type() != new_schema.get_charset_type())) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(ori_schema.get_collation_type()), K(ori_schema.get_collation_type()), K(ret));
}
ObCollationType coll_type = ori_schema.get_collation_type();
for (int64_t i = 0; OB_SUCC(ret) && i < ori_type_info.count(); ++i) {
const ObString& ori_str = ori_type_info.at(i);
const ObString& new_str = new_type_info.at(i);
if (0 != ObCharset::strcmp(coll_type, ori_str.ptr(), ori_str.length(), new_str.ptr(), new_str.length())) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("not support", K(coll_type), K(ori_str), K(new_str), K(ret));
}
}
return ret;
}
int ObDDLResolver::cast_enum_or_set_default_value(const ObColumnSchemaV2& column, ObCastCtx& cast_ctx, ObObj& def_val)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(!def_val.is_string_type())) {
ret = OB_INVALID_DEFAULT;
LOG_WARN("invalid default value type", K(def_val), K(ret));
LOG_USER_ERROR(OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
} else if (OB_UNLIKELY(!ob_is_enumset_tc(column.get_data_type()))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected column type", K(column), K(ret));
} else {
ObExpectType expect_type;
expect_type.set_type(column.get_data_type());
expect_type.set_collation_type(column.get_collation_type());
expect_type.set_type_infos(&column.get_extended_type_info());
if (OB_FAIL(ObObjCaster::to_type(expect_type, cast_ctx, def_val, def_val))) {
ret = OB_INVALID_DEFAULT;
LOG_WARN("fail to cast to enum or set", K(def_val), K(expect_type), K(ret));
LOG_USER_ERROR(OB_INVALID_DEFAULT, column.get_column_name_str().length(), column.get_column_name_str().ptr());
}
}
return ret;
}
int ObDDLResolver::print_expr_to_default_value(
ObRawExpr& expr, share::schema::ObColumnSchemaV2& column, const ObTimeZoneInfo* tz_info)
{
int ret = OB_SUCCESS;
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;
ObObj default_value;
ObRawExprPrinter expr_printer(expr_str_buf, OB_MAX_DEFAULT_VALUE_LENGTH, &pos, tz_info);
if (OB_FAIL(expr_printer.do_print(&expr, T_NONE_SCOPE, true))) {
LOG_WARN("print expr definition failed", K(expr), K(ret));
} else if (FALSE_IT(expr_def.assign_ptr(expr_str_buf, static_cast<int32_t>(pos)))) {
} else if (FALSE_IT(default_value.set_varchar(expr_def))) {
} else if (FALSE_IT(default_value.set_collation_type(ObCharset::get_system_collation()))) {
} else if (OB_FAIL(column.set_cur_default_value(default_value))) {
LOG_WARN("set orig default value failed", K(ret));
} else {
LOG_DEBUG("succ to print_expr_to_default_value", K(expr), K(column), K(default_value), K(expr_def), K(ret));
}
}
return ret;
}
int ObDDLResolver::check_default_value(ObObj& default_value, const common::ObTimeZoneInfoWrap& tz_info_wrap,
const common::ObString* nls_formats, ObIAllocator& allocator, ObTableSchema& table_schema, ObColumnSchemaV2& column)
{
int ret = OB_SUCCESS;
const ObObj input_default_value = default_value;
if (column.is_generated_column()) {
ObString expr_str;
ObResolverParams params;
ObRawExpr* expr = NULL;
ObRawExprFactory expr_factory(allocator);
ObSQLSessionInfo empty_session;
params.expr_factory_ = &expr_factory;
params.allocator_ = &allocator;
params.session_info_ = &empty_session;
if (OB_FAIL(empty_session.test_init(0, 0, 0, &allocator))) {
LOG_WARN("init empty session failed", K(ret));
} else if (OB_FAIL(empty_session.load_default_sys_variable(false, false))) {
LOG_WARN("session load default system variable failed", K(ret));
} else if (OB_FAIL(input_default_value.get_string(expr_str))) {
LOG_WARN("get expr string from default value failed", K(ret), K(input_default_value));
} else if (OB_FAIL(ObResolverUtils::resolve_generated_column_expr(
params, expr_str, table_schema, column, expr, ObResolverUtils::CHECK_FOR_GENERATED_COLUMN))) {
LOG_WARN("resolve generated column expr failed", K(ret));
} else if (column.get_meta_type().is_null()) {
column.set_data_type(expr->get_data_type());
column.set_collation_type(expr->get_collation_type());
column.set_accuracy(expr->get_accuracy());
}
} else if (column.is_default_expr_v2_column()) {
ObString expr_str;
ObResolverParams params;
ObRawExpr* expr = NULL;
ObRawExprFactory expr_factory(allocator);
ObSQLSessionInfo empty_session;
ParamStore empty_param_list((ObWrapperAllocator(allocator)));
params.expr_factory_ = &expr_factory;
params.allocator_ = &allocator;
params.session_info_ = &empty_session;
params.param_list_ = &empty_param_list;
common::ObObj tmp_default_value;
common::ObObj tmp_dest_obj;
const ObObj* tmp_res_obj = NULL;
common::ObObj tmp_dest_obj_null;
const bool is_strict = true; // oracle mode
const ObObjType data_type = column.get_data_type();
const ObAccuracy& accuracy = column.get_accuracy();
const ObCollationType collation_type = column.get_collation_type();
const ObDataTypeCastParams dtc_params(
tz_info_wrap.get_time_zone_info(), nls_formats, CS_TYPE_INVALID, CS_TYPE_INVALID, CS_TYPE_UTF8MB4_GENERAL_CI);
ObCastCtx cast_ctx(&allocator, &dtc_params, CM_NONE, column.get_collation_type());
if (OB_FAIL(empty_session.test_init(0, 0, 0, &allocator))) {
LOG_WARN("init empty session failed", K(ret));
} else if (OB_FAIL(empty_session.load_default_sys_variable(false, false))) {
LOG_WARN("session load default system variable failed", K(ret));
} else if (OB_FAIL(empty_session.set_tz_info_wrap(tz_info_wrap))) {
LOG_WARN("fail to set set_tz_info_wrap", K(ret));
} else if (FALSE_IT(empty_session.set_nls_formats(nls_formats))) {
} else if (FALSE_IT(empty_session.set_compatibility_mode(
share::is_oracle_mode() ? ObCompatibilityMode::ORACLE_MODE : ObCompatibilityMode::MYSQL_MODE))) {
} else if (FALSE_IT(
empty_session.set_sql_mode(share::is_oracle_mode() ? DEFAULT_ORACLE_MODE : DEFAULT_MYSQL_MODE))) {
} else if (OB_FAIL(input_default_value.get_string(expr_str))) {
LOG_WARN("get expr string from default value failed", K(ret), K(input_default_value));
} else if (OB_FAIL(ObResolverUtils::resolve_default_expr_v2_column_expr(params, expr_str, column, expr))) {
LOG_WARN("resolve expr_default expr failed", K(expr_str), K(column), K(ret));
} else if (OB_FAIL(ObSQLUtils::calc_simple_expr_without_row(stmt::StmtType::T_NONE,
params.session_info_,
expr,
tmp_default_value,
params.param_list_,
allocator))) {
LOG_WARN("Failed to get simple expr value", K(ret));
} else if (OB_FAIL(ObObjCaster::to_type(data_type, cast_ctx, tmp_default_value, tmp_dest_obj, tmp_res_obj))) {
LOG_WARN("cast obj failed, ",
"src type",
tmp_default_value.get_type(),
"dest type",
data_type,
K(tmp_default_value),
K(ret));
} else if (OB_ISNULL(tmp_res_obj)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cast obj failed, ",
"src type",
tmp_default_value.get_type(),
"dest type",
data_type,
K(tmp_default_value),
K(ret));
} else if (OB_FAIL(obj_collation_check(is_strict, collation_type, *const_cast<ObObj*>(tmp_res_obj)))) {
LOG_WARN("failed to check collation", K(ret), K(collation_type), K(tmp_dest_obj));
} else if (OB_FAIL(
obj_accuracy_check(cast_ctx, accuracy, collation_type, *tmp_res_obj, tmp_dest_obj, tmp_res_obj))) {
LOG_WARN("failed to check accuracy", K(ret), K(accuracy), K(collation_type), KPC(tmp_res_obj));
} else if (0 == input_default_value.get_string().compare("''")) {
// if default is '', we should store '' instead of NULL.
// FIXME::when observer differentiate '' and null, we can delete this code
tmp_dest_obj_null.set_varchar(input_default_value.get_string());
tmp_dest_obj_null.set_collation_type(ObCharset::get_system_collation());
if (OB_FAIL(column.set_cur_default_value(tmp_dest_obj_null))) {
LOG_WARN("set orig default value failed", K(ret));
}
} else if (OB_FAIL(print_expr_to_default_value(*expr, column, tz_info_wrap.get_time_zone_info()))) {
LOG_WARN("fail to print_expr_to_default_value", KPC(expr), K(column), K(ret));
}
LOG_DEBUG("finish check default value",
K(input_default_value),
K(expr_str),
K(tmp_default_value),
K(tmp_dest_obj),
K(tmp_dest_obj_null),
KPC(expr),
K(ret));
} else {
if (OB_FAIL(cast_default_value(default_value, tz_info_wrap.get_time_zone_info(), nls_formats, allocator, column))) {
LOG_WARN(
"fail to cast default value!", K(default_value), KPC(tz_info_wrap.get_time_zone_info()), K(column), K(ret));
} else if (OB_FAIL(check_default_value_length(default_value, column))) {
LOG_WARN("fail to check default value length", K(default_value), K(column), K(ret));
} else {
default_value.set_collation_type(column.get_collation_type());
LOG_DEBUG("succ to set default value", K(input_default_value), K(default_value), K(column), K(ret));
}
}
return ret;
}
int ObDDLResolver::calc_default_value(share::schema::ObColumnSchemaV2& column, common::ObObj& default_value,
const common::ObTimeZoneInfoWrap& tz_info_wrap, const common::ObString* nls_formats,
common::ObIAllocator& allocator)
{
int ret = OB_SUCCESS;
if (IS_DEFAULT_NOW_OBJ(default_value)) {
int64_t cur_time = ObTimeUtility::current_time();
ObTimeConverter::round_datetime(column.get_data_scale(), cur_time);
switch (column.get_data_type()) {
case ObDateTimeType: {
int64_t dt_value = 0;
if (OB_FAIL(ObTimeConverter::timestamp_to_datetime(cur_time, tz_info_wrap.get_time_zone_info(), dt_value))) {
LOG_WARN("failed to convert timestamp to datetime", K(ret));
} else {
ObTimeConverter::round_datetime(column.get_data_scale(), dt_value);
default_value.set_datetime(dt_value);
}
break;
}
case ObTimestampType: {
ObTimeConverter::round_datetime(column.get_data_scale(), cur_time);
default_value.set_timestamp(cur_time);
break;
}
default: {
ret = OB_NOT_SUPPORTED;
LOG_WARN("UnKnown type!", "default value type", column.get_data_type(), K(ret));
break;
}
}
} else if (column.is_default_expr_v2_column()) {
ObString expr_str;
ObResolverParams params;
ObRawExpr* expr = NULL;
ObRawExprFactory expr_factory(allocator);
ObSQLSessionInfo empty_session;
ParamStore empty_param_list((ObWrapperAllocator(allocator)));
params.expr_factory_ = &expr_factory;
params.allocator_ = &allocator;
params.session_info_ = &empty_session;
params.param_list_ = &empty_param_list;
if (OB_FAIL(empty_session.test_init(0, 0, 0, &allocator))) {
LOG_WARN("init empty session failed", K(ret));
} else if (OB_FAIL(empty_session.load_default_sys_variable(false, false))) {
LOG_WARN("session load default system variable failed", K(ret));
} else if (OB_FAIL(empty_session.set_tz_info_wrap(tz_info_wrap))) {
LOG_WARN("fail to set set_tz_info_wrap", K(ret));
} else if (FALSE_IT(empty_session.set_nls_formats(nls_formats))) {
} else if (FALSE_IT(empty_session.set_compatibility_mode(
share::is_oracle_mode() ? ObCompatibilityMode::ORACLE_MODE : ObCompatibilityMode::MYSQL_MODE))) {
} else if (FALSE_IT(
empty_session.set_sql_mode(share::is_oracle_mode() ? DEFAULT_ORACLE_MODE : DEFAULT_MYSQL_MODE))) {
} else if (OB_FAIL(default_value.get_string(expr_str))) {
LOG_WARN("get expr string from default value failed", K(ret), K(default_value));
} else if (OB_FAIL(ObResolverUtils::resolve_default_expr_v2_column_expr(params, expr_str, column, expr))) {
LOG_WARN("resolve expr_default expr failed", K(ret));
} else if (OB_FAIL(ObSQLUtils::calc_simple_expr_without_row(
stmt::StmtType::T_NONE, params.session_info_, expr, default_value, params.param_list_, allocator))) {
LOG_WARN("Failed to get simple expr value", K(ret));
} else {
ObObj dest_obj;
const ObDataTypeCastParams dtc_params(
tz_info_wrap.get_time_zone_info(), nls_formats, CS_TYPE_INVALID, CS_TYPE_INVALID, CS_TYPE_UTF8MB4_GENERAL_CI);
ObCastCtx cast_ctx(&allocator, &dtc_params, CM_NONE, column.get_collation_type());
if (OB_FAIL(ObObjCaster::to_type(column.get_data_type(), cast_ctx, default_value, dest_obj))) {
LOG_WARN("cast obj failed, ",
"src type",
default_value.get_type(),
"dest type",
column.get_data_type(),
K(default_value),
K(ret));
} else {
dest_obj.set_scale(column.get_data_scale());
default_value = dest_obj;
}
}
LOG_DEBUG("finish calc default value", K(column), K(expr_str), K(default_value), KPC(expr), K(ret));
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("it should not arrive here", K(ret), K(default_value), K(column), K(lbt()));
}
return ret;
}
int ObDDLResolver::resolve_range_partition_elements(ParseNode* node, const bool is_subpartition,
const ObPartitionFuncType part_type, const int64_t expr_num, ObIArray<ObRawExpr*>& range_value_exprs,
ObIArray<ObPartition>& partitions, ObIArray<ObSubPartition>& subpartitions, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(node) || OB_ISNULL(stmt_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null or stmt is null", K(ret), K(node), KP(stmt_));
} else if (expr_num <= 0) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("expr num is invalid", K(ret), K(expr_num));
} else {
int64_t partition_num = node->num_child_;
ParseNode* partition_expr_list = node;
ObPartition partition;
ObSubPartition subpartition;
bool use_part_id = false;
const ObCreateTablegroupStmt* tablegroup_stmt = static_cast<ObCreateTablegroupStmt*>(stmt_);
bool has_empty_name = false;
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; i++) {
subpartition.reset();
partition.reset();
ParseNode* element_node = partition_expr_list->children_[i];
if (OB_ISNULL(element_node) || OB_ISNULL(element_node->children_[PARTITION_ELEMENT_NODE])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition expr list node is null", K(ret), K(element_node));
} else if ((OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]) ||
OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE])) &&
!is_oracle_mode()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition expr list node is null", K(ret), K(element_node));
} else {
ObString partition_name;
if (OB_NOT_NULL(element_node->children_[PARTITION_NAME_NODE])) {
ParseNode* partition_name_node = element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE];
partition_name.assign_ptr(
partition_name_node->str_value_, static_cast<int32_t>(partition_name_node->str_len_));
} else if (is_subpartition) {
subpartition.set_is_empty_partition_name(true);
has_empty_name = true;
} else {
partition.set_is_empty_partition_name(true);
has_empty_name = true;
}
ParseNode* expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE];
if (partition_name.length() > OB_MAX_PARTITION_NAME_LENGTH) {
ret = OB_ERR_TOO_LONG_IDENT;
} else if (T_EXPR_LIST != expr_list_node->type_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr_list_node->type_ is not T_EXPR_LIST", K(ret));
} else if (expr_num != expr_list_node->num_child_) {
ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
LOG_WARN("Inconsistency in usage of column lists for partitioning near",
K(ret),
K(expr_num),
"num_child",
expr_list_node->num_child_);
} else if ((is_subpartition) && OB_NOT_NULL(element_node->children_[PART_ID_NODE])) {
ret = OB_ERR_PARSE_SQL;
LOG_WARN("not support subpartition with part_id", K(ret), K(is_subpartition), K(in_tablegroup));
} else if (use_part_id && OB_ISNULL(element_node->children_[PART_ID_NODE])) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Should speicify part id for all parts", K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "part id which should speicify part id for all parts");
} else {
if (is_subpartition) {
subpartition.set_part_id(ObSubPartition::TEMPLATE_PART_ID);
subpartition.set_sub_part_id(i);
if (OB_FAIL(subpartition.set_part_name(partition_name))) {
LOG_WARN("Failed to set part name", K(ret));
} else {
ret = subpartitions.push_back(subpartition);
}
} else {
if (nullptr == element_node->children_[PART_ID_NODE]) {
partition.set_part_id(i);
} else if (OB_ISNULL(tablegroup_stmt) || OB_ISNULL(element_node->children_[PART_ID_NODE]->children_[0])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("not create tablegroup stmt or part id node is null", K(ret), "stmt", *stmt_);
} else {
bool valid = false;
const int64_t max_used_part_id = tablegroup_stmt->get_max_used_part_id();
const int64_t part_id = static_cast<int32_t>(element_node->children_[PART_ID_NODE]->children_[0]->value_);
partition.set_part_id(part_id);
if (OB_FAIL(check_partid_valid(tablegroup_stmt, part_id, max_used_part_id, valid))) {
LOG_WARN("part id not valid", K(ret));
} else if (!valid) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("part id not valid", K(ret));
} else if (0 == i) {
use_part_id = true;
} else if (!use_part_id) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Should speicify part id for all parts", K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "part id which should speicify part id for all parts");
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(partition.set_part_name(partition_name))) {
LOG_WARN("Failed to set part name", K(ret));
} else {
ret = partitions.push_back(partition);
}
}
if (OB_FAIL(ret)) {
// do nothing
} else if (OB_FAIL(resolve_range_value_exprs(
expr_list_node, part_type, partition_name, range_value_exprs, in_tablegroup))) {
LOG_WARN("fail to resolve range partition element", K(ret));
}
}
}
}
if (OB_UNLIKELY(has_empty_name) &&
(stmt::T_CREATE_TABLE == stmt_->get_stmt_type() || stmt::T_CREATE_TABLEGROUP == stmt_->get_stmt_type() ||
stmt::T_CREATE_INDEX == stmt_->get_stmt_type())) {
if (OB_FAIL(create_name_for_empty_partition(is_subpartition, partitions, subpartitions))) {
LOG_WARN("failed to create name for empty [sub]partitions", K(ret));
}
}
}
return ret;
}
int ObDDLResolver::resolve_range_partition_elements(ParseNode* node, const bool is_subpartition,
const ObPartitionFuncType part_type, ObIArray<ObRawExpr*>& range_value_exprs, ObIArray<ObPartition>& partitions,
ObIArray<ObSubPartition>& subpartitions, int64_t& expr_num, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
expr_num = OB_INVALID_INDEX;
if (OB_ISNULL(node)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null or stmt is null", K(ret), K(node));
} else {
int64_t partition_num = node->num_child_;
ParseNode* partition_expr_list = node;
ObPartition partition;
ObSubPartition subpartition;
bool has_empty_name = false;
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; i++) {
subpartition.reset();
partition.reset();
ParseNode* element_node = partition_expr_list->children_[i];
if (OB_ISNULL(element_node) || OB_ISNULL(element_node->children_[PARTITION_ELEMENT_NODE])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition expr list node is null", K(ret), K(element_node));
} else if ((OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]) ||
OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE])) &&
!is_oracle_mode()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition expr list node is null", K(ret), K(element_node));
} else {
ObString partition_name;
if (OB_NOT_NULL(element_node->children_[PARTITION_NAME_NODE])) {
ParseNode* partition_name_node = element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE];
partition_name.assign_ptr(
partition_name_node->str_value_, static_cast<int32_t>(partition_name_node->str_len_));
} else if (is_subpartition) {
subpartition.set_is_empty_partition_name(true);
bool has_empty_name = false;
} else {
partition.set_is_empty_partition_name(true);
bool has_empty_name = false;
}
ParseNode* expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE];
if (partition_name.length() > OB_MAX_PARTITION_NAME_LENGTH) {
ret = OB_ERR_TOO_LONG_IDENT;
} else if (T_EXPR_LIST != expr_list_node->type_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr_list_node->type_ is not T_EXPR_LIST", K(ret));
} else if (OB_INVALID_INDEX != expr_num && expr_num != expr_list_node->num_child_) {
ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
LOG_WARN("Inconsistency in usage of column lists for partitioning near",
K(ret),
K(expr_num),
"num_child",
expr_list_node->num_child_);
} else if ((in_tablegroup || is_subpartition) && OB_NOT_NULL(element_node->children_[PART_ID_NODE])) {
ret = OB_ERR_PARSE_SQL;
LOG_WARN("not support tablegroup or subpartition with part_id", K(ret), K(is_subpartition), K(in_tablegroup));
} else {
if (is_subpartition) {
subpartition.set_part_id(ObSubPartition::TEMPLATE_PART_ID);
subpartition.set_sub_part_id(i);
if (OB_FAIL(subpartition.set_part_name(partition_name))) {
LOG_WARN("Failed to set part name", K(ret));
} else {
ret = subpartitions.push_back(subpartition);
}
} else {
partition.set_part_id(i);
if (OB_FAIL(partition.set_part_name(partition_name))) {
LOG_WARN("Failed to set part name", K(ret));
} else {
ret = partitions.push_back(partition);
}
}
if (OB_FAIL(ret)) {
// do nothing
} else if (OB_FAIL(resolve_range_value_exprs(
expr_list_node, part_type, partition_name, range_value_exprs, in_tablegroup))) {
LOG_WARN("fail to resolve range partition element", K(ret));
} else {
expr_num = expr_list_node->num_child_;
}
}
}
}
if (OB_UNLIKELY(has_empty_name) &&
(stmt::T_CREATE_TABLE == stmt_->get_stmt_type() || stmt::T_CREATE_TABLEGROUP == stmt_->get_stmt_type() ||
stmt::T_CREATE_INDEX == stmt_->get_stmt_type())) {
if (OB_FAIL(create_name_for_empty_partition(is_subpartition, partitions, subpartitions))) {
LOG_WARN("failed to create name for empty [sub]partitions", K(ret));
}
}
}
return ret;
}
int ObDDLResolver::resolve_range_value_exprs(ParseNode* expr_list_node, const ObPartitionFuncType part_type,
const ObString& partition_name, ObIArray<ObRawExpr*>& range_value_exprs, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(expr_list_node)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null or stmt is null", K(ret), K(expr_list_node));
} else {
for (int64_t j = 0; OB_SUCC(ret) && j < expr_list_node->num_child_; j++) {
if (OB_ISNULL(expr_list_node->children_[j])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null", K(ret));
} else if (T_MAXVALUE == expr_list_node->children_[j]->type_) {
ObRawExpr* maxvalue_expr = NULL;
ObConstRawExpr* c_expr = NULL;
c_expr = (ObConstRawExpr*)allocator_->alloc(sizeof(ObConstRawExpr));
if (NULL != c_expr) {
c_expr = new (c_expr) ObConstRawExpr();
maxvalue_expr = c_expr;
maxvalue_expr->set_data_type(common::ObMaxType);
if (OB_FAIL(range_value_exprs.push_back(maxvalue_expr))) {
LOG_WARN("array push back fail", K(ret));
}
} else {
ret = OB_ALLOCATE_MEMORY_FAILED;
}
} else if (T_NULL == expr_list_node->children_[j]->type_) {
ret = OB_EER_NULL_IN_VALUES_LESS_THAN;
LOG_WARN("null value is not allowed in less than", K(ret));
} else if (T_EXPR_LIST != expr_list_node->children_[j]->type_) {
ObRawExpr* part_value_expr = NULL;
if (OB_FAIL(ObResolverUtils::resolve_partition_range_value_expr(
params_, *(expr_list_node->children_[j]), partition_name, part_type, part_value_expr, in_tablegroup))) {
LOG_WARN("resolve partition expr failed", K(ret));
} else if (OB_FAIL(range_value_exprs.push_back(part_value_expr))) {
LOG_WARN("array push back fail", K(ret));
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr_node type is error", K(ret));
}
}
}
return ret;
}
int ObDDLResolver::resolve_list_partition_elements(ParseNode* node, const bool is_subpartition,
const ObPartitionFuncType part_type, int64_t& expr_num, ObDDLStmt::array_t& list_value_exprs,
ObIArray<ObPartition>& partitions, ObIArray<ObSubPartition>& subpartitions, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(node) || OB_ISNULL(stmt_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null or stmt is null", K(ret), K(node), K(stmt_));
} else {
int64_t partition_num = node->num_child_;
ParseNode* partition_expr_list = node;
ObPartition partition;
ObSubPartition subpartition;
int64_t first_non_default_value_idx = OB_INVALID_INDEX;
bool use_part_id = false;
const sql::ObCreateTablegroupStmt* tablegroup_stmt = static_cast<ObCreateTablegroupStmt*>(stmt_);
bool has_empty_name = false;
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; i++) {
subpartition.reset();
partition.reset();
ParseNode* element_node = partition_expr_list->children_[i];
if (OB_ISNULL(element_node) || OB_ISNULL(element_node->children_[PARTITION_ELEMENT_NODE])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition expr list node is null", K(ret), K(element_node));
} else if ((OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]) ||
OB_ISNULL(element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE])) &&
!is_oracle_mode()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition expr list node is null", K(ret), K(element_node));
} else if (is_subpartition && OB_NOT_NULL(element_node->children_[PART_ID_NODE])) {
ret = OB_ERR_PARSE_SQL;
LOG_WARN("subpartition can not specify part id", K(ret), K(i), K(is_subpartition), K(in_tablegroup));
} else {
ObString partition_name;
if (OB_NOT_NULL(element_node->children_[PARTITION_NAME_NODE])) {
ParseNode* partition_name_node = element_node->children_[PARTITION_NAME_NODE]->children_[NAMENODE];
partition_name.assign_ptr(
partition_name_node->str_value_, static_cast<int32_t>(partition_name_node->str_len_));
} else if (is_subpartition) {
subpartition.set_is_empty_partition_name(true);
has_empty_name = true;
} else {
partition.set_is_empty_partition_name(true);
has_empty_name = true;
}
ParseNode* expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE];
if (partition_name.length() > OB_MAX_PARTITION_NAME_LENGTH) {
ret = OB_ERR_TOO_LONG_IDENT;
} else if (T_EXPR_LIST != expr_list_node->type_ && T_DEFAULT != expr_list_node->type_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expr_list_node->type_ is not T_EXPR_LIST or T_DEFAULT", K(ret));
}
// add list partition elements to tablegroup schema
if (OB_SUCC(ret)) {
if (is_subpartition) {
subpartition.set_part_id(ObSubPartition::TEMPLATE_PART_ID);
subpartition.set_sub_part_id(i);
if (OB_FAIL(subpartition.set_part_name(partition_name))) {
LOG_WARN("Failed to set part name", K(ret));
} else {
ret = subpartitions.push_back(subpartition);
}
} else {
if (use_part_id && OB_ISNULL(element_node->children_[PART_ID_NODE])) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Should speicify part id for all parts", K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "part id which should speicify part id for all parts");
} else if (nullptr == element_node->children_[PART_ID_NODE]) {
partition.set_part_id(i);
} else if (OB_ISNULL(tablegroup_stmt) || OB_ISNULL(element_node->children_[PART_ID_NODE]->children_[0])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("not create tablegroup stmt or part id node is null", K(ret), "stmt", *stmt_);
} else {
bool valid = false;
const int64_t max_used_part_id = tablegroup_stmt->get_max_used_part_id();
const int64_t part_id = static_cast<int32_t>(element_node->children_[PART_ID_NODE]->children_[0]->value_);
partition.set_part_id(part_id);
if (OB_FAIL(check_partid_valid(tablegroup_stmt, part_id, max_used_part_id, valid))) {
LOG_WARN("part id not valid", K(ret));
} else if (!valid) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("part id not valid", K(ret));
} else if (0 == i) {
use_part_id = true;
} else if (!use_part_id) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Should speicify part id for all parts", K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "part id which should speicify part id for all parts");
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(partition.set_part_name(partition_name))) {
LOG_WARN("Failed to set part name", K(ret));
} else {
ret = partitions.push_back(partition);
}
}
}
if (OB_SUCC(ret)) {
ObOpRawExpr* row_expr = NULL;
if (OB_ISNULL(params_.expr_factory_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (OB_FAIL(params_.expr_factory_->create_raw_expr(T_OP_ROW, row_expr))) {
LOG_WARN("failed to create raw expr", K(ret));
} else if (OB_ISNULL(row_expr)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allcoate memory", K(ret));
} else if (T_DEFAULT == expr_list_node->type_) {
// replace default with max
ObRawExpr* maxvalue_expr = NULL;
ObConstRawExpr* c_expr = NULL;
c_expr = (ObConstRawExpr*)allocator_->alloc(sizeof(ObConstRawExpr));
if (OB_ISNULL(c_expr)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allcoate memory", K(ret));
} else {
c_expr = new (c_expr) ObConstRawExpr();
maxvalue_expr = c_expr;
maxvalue_expr->set_data_type(common::ObMaxType);
if (OB_FAIL(row_expr->add_param_expr(maxvalue_expr))) {
LOG_WARN("failed add param expr", K(ret));
} else if (OB_FAIL(list_value_exprs.push_back(row_expr))) {
LOG_WARN("array push back fail", K(ret));
}
}
} else {
ObSEArray<ObRawExpr*, 16> part_value_exprs;
bool is_all_expr_list = false;
expr_num = OB_INVALID_COUNT;
if (expr_list_node->num_child_ > 0) {
is_all_expr_list = (expr_list_node->children_[0]->type_ == T_EXPR_LIST);
}
for (int64_t j = 0; OB_SUCC(ret) && j < expr_list_node->num_child_; j++) {
part_value_exprs.reset();
if (OB_ISNULL(expr_list_node->children_[j])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null", K(ret));
} else if ((is_all_expr_list && expr_list_node->children_[j]->type_ != T_EXPR_LIST) ||
(!is_all_expr_list && expr_list_node->children_[j]->type_ == T_EXPR_LIST)) {
ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
} else if (OB_FAIL(ObResolverUtils::resolve_partition_list_value_expr(params_,
*(expr_list_node->children_[j]),
partition_name,
part_type,
expr_num,
part_value_exprs,
in_tablegroup))) {
LOG_WARN("resolve partition expr failed", K(ret));
}
for (int64_t k = 0; OB_SUCC(ret) && k < part_value_exprs.count(); k++) {
int64_t idx = row_expr->get_param_count() % expr_num;
ObObjType cur_data_type = part_value_exprs.at(k)->get_data_type();
ObObjType pre_data_type = cur_data_type;
if (first_non_default_value_idx >= 0) {
if (list_value_exprs.at(first_non_default_value_idx)->get_param_count() <= idx) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("value expr num in row is invalid",
K(ret),
K(first_non_default_value_idx),
K(idx),
K(list_value_exprs.at(first_non_default_value_idx)),
KPC(part_value_exprs.at(k)));
} else {
pre_data_type =
list_value_exprs.at(first_non_default_value_idx)->get_param_expr(idx)->get_data_type();
}
} else if (row_expr->get_param_count() > idx) {
pre_data_type = row_expr->get_param_expr(idx)->get_data_type();
}
if (OB_FAIL(ret)) {
// do nothing
} else if (ObMaxType != cur_data_type && ObMaxType != pre_data_type && cur_data_type != pre_data_type) {
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(cur_data_type), K(pre_data_type));
} else if (OB_FAIL(row_expr->add_param_expr(part_value_exprs.at(k)))) {
LOG_WARN("array push back fail", K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (expr_num > 1 && !is_all_expr_list) {
if (row_expr->get_param_count() != 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));
}
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(list_value_exprs.push_back(row_expr))) {
LOG_WARN("array push back fail", K(ret));
} else if (first_non_default_value_idx < 0) {
first_non_default_value_idx = i;
}
}
}
}
}
}
if (OB_UNLIKELY(has_empty_name) &&
(stmt::T_CREATE_TABLE == stmt_->get_stmt_type() || stmt::T_CREATE_TABLEGROUP == stmt_->get_stmt_type() ||
stmt::T_CREATE_INDEX == stmt_->get_stmt_type())) {
if (OB_FAIL(create_name_for_empty_partition(is_subpartition, partitions, subpartitions))) {
LOG_WARN("failed to create name for empty [sub]partitions", K(ret));
}
}
}
return ret;
}
int ObDDLResolver::check_column_in_foreign_key(const ObTableSchema& table_schema, const ObString& column_name)
{
int ret = OB_SUCCESS;
if (table_schema.is_parent_table() || table_schema.is_child_table()) {
const ObColumnSchemaV2* alter_column = table_schema.get_column_schema(column_name);
if (OB_ISNULL(alter_column)) {
// do nothing
} else {
const ObIArray<ObForeignKeyInfo>& foreign_key_infos = table_schema.get_foreign_key_infos();
for (int64_t i = 0; OB_SUCC(ret) && i < foreign_key_infos.count(); i++) {
const ObForeignKeyInfo& foreign_key_info = foreign_key_infos.at(i);
if (table_schema.get_table_id() == foreign_key_info.parent_table_id_) {
for (int64_t j = 0; OB_SUCC(ret) && j < foreign_key_info.parent_column_ids_.count(); j++) {
if (alter_column->get_column_id() == foreign_key_info.parent_column_ids_.at(j)) {
ret = OB_ERR_ALTER_COLUMN_FK;
LOG_USER_ERROR(OB_ERR_ALTER_COLUMN_FK, column_name.length(), column_name.ptr());
}
}
}
if (table_schema.get_table_id() == foreign_key_info.child_table_id_) {
for (int64_t j = 0; OB_SUCC(ret) && j < foreign_key_info.child_column_ids_.count(); j++) {
if (alter_column->get_column_id() == foreign_key_info.child_column_ids_.at(j)) {
ret = OB_ERR_ALTER_COLUMN_FK;
LOG_USER_ERROR(OB_ERR_ALTER_COLUMN_FK, column_name.length(), column_name.ptr());
}
}
}
}
}
}
return ret;
}
int ObDDLResolver::check_column_in_check_constraint_for_oracle(
const share::schema::ObTableSchema& table_schema, const ObString& column_name, ObAlterTableStmt* alter_table_stmt)
{
int ret = OB_SUCCESS;
const ObColumnSchemaV2* alter_column = table_schema.get_column_schema(column_name);
if (OB_ISNULL(alter_column)) {
// do nothing
} else {
for (ObTableSchema::const_constraint_iterator iter = table_schema.constraint_begin();
OB_SUCC(ret) && (iter != table_schema.constraint_end());
++iter) {
if (CONSTRAINT_TYPE_CHECK == (*iter)->get_constraint_type()) {
for (ObConstraint::const_cst_col_iterator cst_col_iter = (*iter)->cst_col_begin();
OB_SUCC(ret) && (cst_col_iter != (*iter)->cst_col_end());
++cst_col_iter) {
if (*cst_col_iter == alter_column->get_column_id()) {
if (0 == (*iter)->get_column_cnt()) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "check cst don't have column info", K(ret), K(**iter));
} else if (1 == (*iter)->get_column_cnt()) {
// drop check constraint cascaded
AlterTableSchema& alter_table_schema = alter_table_stmt->get_alter_table_arg().alter_table_schema_;
if (OB_FAIL(alter_table_schema.add_constraint(**iter))) {
SQL_RESV_LOG(WARN, "add constraint failed!", K(ret), K(**iter));
} else {
alter_table_stmt->get_alter_table_arg().alter_constraint_type_ = ObAlterTableArg::DROP_CONSTRAINT;
}
} else {
// if check constraint includes more than one column, throw
ret = OB_ERR_DROP_COL_REFERENCED_MULTI_COLS_CONSTRAINT;
SQL_RESV_LOG(WARN,
"column is referenced in a multi-column constraint",
K(ret),
K(alter_column->get_column_name_str()),
K((*iter)->get_constraint_name_str()),
K((*iter)->get_check_expr_str()));
}
}
}
}
}
}
return ret;
}
int ObDDLResolver::check_column_in_foreign_key_for_oracle(
const ObTableSchema& table_schema, const ObString& column_name, ObAlterTableStmt* alter_table_stmt)
{
int ret = OB_SUCCESS;
if (table_schema.is_parent_table() || table_schema.is_child_table()) {
const ObColumnSchemaV2* alter_column = table_schema.get_column_schema(column_name);
if (OB_ISNULL(alter_column)) {
// do full check in RS
} else {
const ObIArray<ObForeignKeyInfo>& foreign_key_infos = table_schema.get_foreign_key_infos();
for (int64_t i = 0; OB_SUCC(ret) && i < foreign_key_infos.count(); i++) {
const ObForeignKeyInfo& foreign_key_info = foreign_key_infos.at(i);
// column in parent table can't be deleted
if (OB_SUCC(ret) && table_schema.get_table_id() == foreign_key_info.parent_table_id_) {
for (int64_t j = 0; OB_SUCC(ret) && j < foreign_key_info.parent_column_ids_.count(); j++) {
if (alter_column->get_column_id() == foreign_key_info.parent_column_ids_.at(j)) {
ret = OB_ERR_DROP_PARENT_KEY_COLUMN;
}
}
}
if (OB_SUCC(ret) && table_schema.get_table_id() == foreign_key_info.child_table_id_ &&
foreign_key_info.child_column_ids_.count() > 1) {
for (int64_t j = 0; OB_SUCC(ret) && j < foreign_key_info.child_column_ids_.count(); j++) {
if (alter_column->get_column_id() == foreign_key_info.child_column_ids_.at(j)) {
ret = OB_ERR_MODIFY_OR_DROP_MULTI_COLUMN_CONSTRAINT;
}
}
}
if (OB_SUCC(ret) && table_schema.get_table_id() == foreign_key_info.child_table_id_ &&
foreign_key_info.child_column_ids_.count() == 1) {
if (alter_column->get_column_id() == foreign_key_info.child_column_ids_.at(0)) {
ObDropForeignKeyArg* foreign_key_arg = NULL;
void* tmp_ptr = NULL;
if (OB_ISNULL(tmp_ptr = allocator_->alloc(sizeof(ObDropForeignKeyArg)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
SQL_RESV_LOG(ERROR, "failed to allocate memory", K(ret));
} else if (FALSE_IT(foreign_key_arg = new (tmp_ptr) ObDropForeignKeyArg())) {
} else if (FALSE_IT(foreign_key_arg->foreign_key_name_.assign_ptr(
foreign_key_info.foreign_key_name_.ptr(), foreign_key_info.foreign_key_name_.length()))) {
} else if (OB_ISNULL(alter_table_stmt)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "alter table stmt should not be null", K(ret));
} else if (OB_FAIL(alter_table_stmt->add_index_arg(foreign_key_arg))) {
SQL_RESV_LOG(WARN, "add index to drop_index_list failed!", K(ret));
} else {
alter_table_stmt->set_alter_table_index();
}
}
}
}
}
}
return ret;
}
bool ObDDLResolver::is_ids_match(const ObIArray<uint64_t>& src_list, const ObIArray<uint64_t>& dest_list)
{
bool is_match = true;
ObSEArray<uint64_t, 8> tmp_src_list;
ObSEArray<uint64_t, 8> tmp_dest_list;
if (src_list.count() != dest_list.count()) {
is_match = false;
} else {
for (int64_t i = 0; i < src_list.count(); ++i) {
tmp_src_list.push_back(src_list.at(i));
tmp_dest_list.push_back(dest_list.at(i));
}
std::sort(tmp_src_list.begin(), tmp_src_list.end());
std::sort(tmp_dest_list.begin(), tmp_dest_list.end());
for (int64_t i = 0; is_match && i < tmp_src_list.count(); ++i) {
if (tmp_src_list.at(i) != tmp_dest_list.at(i)) {
is_match = false;
}
}
}
return is_match;
}
int ObDDLResolver::check_index_columns_equal_foreign_key(
const ObTableSchema& table_schema, const ObTableSchema& index_table_schema)
{
int ret = OB_SUCCESS;
if (table_schema.is_child_table()) {
ObString index_name;
ObSEArray<uint64_t, 8> index_column_ids;
const ObIndexInfo& index_info = index_table_schema.get_index_info();
if (OB_FAIL(index_info.get_column_ids(index_column_ids))) {
LOG_WARN("failed to get column ids from ObRowkeyInfo", K(ret));
} else if (OB_FAIL(index_table_schema.get_index_name(index_name))) {
LOG_WARN("failed to get index name", K(ret));
}
const ObIArray<ObForeignKeyInfo>& foreign_key_infos = table_schema.get_foreign_key_infos();
for (int64_t i = 0; OB_SUCC(ret) && i < foreign_key_infos.count(); ++i) {
const ObForeignKeyInfo& foreign_key_info = foreign_key_infos.at(i);
const int64_t child_column_num = foreign_key_info.child_column_ids_.count();
const uint64_t data_table_id = index_table_schema.get_data_table_id();
if (0 == child_column_num) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("expected foreign key columns num", K(ret), K(child_column_num));
}
if (OB_SUCC(ret)) {
if (data_table_id == foreign_key_info.child_table_id_) {
if (child_column_num == index_table_schema.get_index_column_number()) {
if (is_ids_match(index_column_ids, foreign_key_info.child_column_ids_)) {
ret = OB_ERR_ALTER_COLUMN_FK;
LOG_USER_ERROR(OB_ERR_ALTER_COLUMN_FK, index_name.length(), index_name.ptr());
}
}
} // child_table_id_
}
} // for
}
return ret;
}
// for mysql mode
// in mysql mode: index_1(c1, c2) = index_2(c2, c1)
int ObDDLResolver::check_indexes_on_same_cols(const ObTableSchema& table_schema,
const share::schema::ObTableSchema& input_index_table_schema, ObSchemaChecker& schema_checker,
bool& has_other_indexes_on_same_cols)
{
int ret = OB_SUCCESS;
uint64_t same_indexes_cnt = 0;
ObSEArray<ObString, 8> input_index_columns_name;
has_other_indexes_on_same_cols = false;
ObSEArray<ObAuxTableMetaInfo, 16> simple_index_infos;
if (OB_FAIL(ObResolverUtils::get_columns_name_from_index_table_schema(
input_index_table_schema, input_index_columns_name))) {
LOG_WARN("get columns name from input index table schema failed", K(ret));
} else if (OB_FAIL(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) && !has_other_indexes_on_same_cols && i < simple_index_infos.count(); ++i) {
const ObTableSchema* index_table_schema = NULL;
bool is_match = false;
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 {
ObSEArray<ObString, 8> index_columns_name;
if (OB_FAIL(ObResolverUtils::get_columns_name_from_index_table_schema(*index_table_schema, index_columns_name))) {
LOG_WARN("get columns name from compared index table schema failed", K(ret));
} else if (OB_FAIL(
ObResolverUtils::check_match_columns(input_index_columns_name, index_columns_name, is_match))) {
LOG_WARN("Failed to check_match_columns", K(ret));
} else if (true == is_match) {
++same_indexes_cnt;
if (same_indexes_cnt > 1) {
has_other_indexes_on_same_cols = true;
}
}
}
}
return ret;
}
// for oracle mode
// in oracle mode: index_1(c1, c2) != index_2(c2, c1)
int ObDDLResolver::check_indexes_on_same_cols(const ObTableSchema& table_schema,
const ObCreateIndexArg& create_index_arg, ObSchemaChecker& schema_checker, bool& has_other_indexes_on_same_cols)
{
int ret = OB_SUCCESS;
has_other_indexes_on_same_cols = false;
ObSEArray<ObAuxTableMetaInfo, 16> simple_index_infos;
if (OB_FAIL(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) && !has_other_indexes_on_same_cols && 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 (OB_FAIL(ObResolverUtils::check_match_columns_strict_with_order(
index_table_schema, create_index_arg, has_other_indexes_on_same_cols))) {
LOG_WARN("Failed to check_match_columns", K(ret));
}
}
return ret;
}
int ObDDLResolver::check_index_name_duplicate(const ObTableSchema& table_schema,
const ObCreateIndexArg& create_index_arg, ObSchemaChecker& schema_checker, bool& has_same_index_name)
{
int ret = OB_SUCCESS;
has_same_index_name = false;
ObString index_name;
ObSEArray<ObAuxTableMetaInfo, 16> simple_index_infos;
if (OB_FAIL(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) && !has_same_index_name && 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 (OB_FAIL(index_table_schema->get_index_name(index_name))) {
LOG_WARN("Failed to get_index_name", K(ret));
} else if (0 == index_name.compare(create_index_arg.index_name_)) {
has_same_index_name = true;
}
}
return ret;
}
// child 5 of root node, resolve index partition node,
// 1 this index is global, we need to first generate index schema,
// than resolve global index partition info
// 2 this index is local, an error is raised since we cannot specify
// partition info for a local index
int ObDDLResolver::resolve_index_partition_node(ParseNode* index_partition_node, ObCreateIndexStmt* crt_idx_stmt)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(NULL == index_partition_node) || OB_UNLIKELY(NULL == crt_idx_stmt)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret), KP(index_partition_node), KP(crt_idx_stmt));
} else {
ObTableSchema& index_schema = crt_idx_stmt->get_create_index_arg().index_schema_;
if (NULL == index_partition_node) {
// part method is not specified
} else if (!global_) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("partitioned local index is not supported", K(ret));
LOG_USER_ERROR(OB_NOT_SUPPORTED, "partitioned local index");
} else if (!index_schema.is_global_index_table()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN(
"non global index with partition option not supported", K(ret), "index_type", index_schema.get_index_type());
LOG_USER_ERROR(OB_NOT_SUPPORTED, "non global index with partition option");
} else {
if (OB_FAIL(resolve_partition_node(crt_idx_stmt, index_partition_node, index_schema))) {
LOG_WARN("failed to resolve partition node", K(ret));
// check valid max_used_part_id
} else if (OB_FAIL(check_max_used_part_id_valid(index_schema, max_used_part_id_))) {
LOG_WARN("max used part id valid", K(ret), K(max_used_part_id_), K(index_schema));
} else {
crt_idx_stmt->set_max_used_part_id(max_used_part_id_);
}
if (OB_FAIL(ret)) {
} else if (PARTITION_LEVEL_ZERO == index_schema.get_part_level() ||
PARTITION_LEVEL_ONE == index_schema.get_part_level()) {
// good
} else if (PARTITION_LEVEL_TWO == index_schema.get_part_level()) {
ret = OB_NOT_SUPPORTED;
LOG_USER_ERROR(OB_NOT_SUPPORTED, "index table with sub-partitions");
LOG_WARN("index table with two level partitions not support", K(ret));
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(check_key_cover_partition_column(crt_idx_stmt, index_schema))) {
LOG_WARN("fail to check key cover partition column", K(ret));
}
}
return ret;
}
int ObDDLResolver::check_key_cover_partition_keys(const bool is_range_part,
const common::ObPartitionKeyInfo& part_key_info, share::schema::ObTableSchema& index_schema)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < part_key_info.get_size(); ++i) {
ObSEArray<uint64_t, 8> cascaded_columns;
uint64_t column_id = OB_INVALID_ARGUMENT;
const ObColumnSchemaV2* column_schema = NULL;
if (OB_FAIL(part_key_info.get_column_id(i, column_id))) {
LOG_WARN("fail to get column id", K(ret));
} else if (NULL == (column_schema = index_schema.get_column_schema(column_id))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("column schema is null", K(ret));
} else if (column_schema->get_index_position() > 0) {
if (is_range_part) {
if (column_schema->get_index_position() != i + 1) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("partition columns not prefix of index columns not support", K(ret));
LOG_USER_ERROR(OB_NOT_SUPPORTED, "partition columns not prefix of index columns");
}
}
} else if (!column_schema->is_generated_column()) {
ret = OB_EER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF;
LOG_WARN("global index should cover all partition column of global index", K(ret));
LOG_USER_ERROR(OB_EER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF, "GLOBAL INDEX");
} else if (is_range_part) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("range partition on generated column in global index not support", K(ret));
LOG_USER_ERROR(OB_NOT_SUPPORTED, "range partition on generated column in global index");
} else if (OB_FAIL(column_schema->get_cascaded_column_ids(cascaded_columns))) {
LOG_WARN("fail to get cascaded columns ids", K(ret));
} else {
for (int64_t j = 0; OB_SUCC(ret) && j < cascaded_columns.count(); ++j) {
uint64_t cascaded_column_id = cascaded_columns.at(j);
const ObColumnSchemaV2* cascaded_column = NULL;
if (NULL == (cascaded_column = index_schema.get_column_schema(cascaded_column_id))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("column schema is null", K(ret));
} else if (column_schema->get_index_position() > 0) {
// good, caccaded column is part the index column
} else {
ret = OB_EER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF;
LOG_WARN("global index should cover all partition column of global index", K(ret));
LOG_USER_ERROR(OB_EER_UNIQUE_KEY_NEED_ALL_FIELDS_IN_PF, "GLOBAL INDEX");
}
}
}
}
return ret;
}
int ObDDLResolver::check_key_cover_partition_column(ObCreateIndexStmt* crt_idx_stmt, ObTableSchema& index_schema)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(NULL == crt_idx_stmt)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret));
} else if (global_) {
if (INDEX_TYPE_NORMAL_GLOBAL == crt_idx_stmt->get_create_index_arg().index_type_ ||
INDEX_TYPE_UNIQUE_GLOBAL == crt_idx_stmt->get_create_index_arg().index_type_) {
const common::ObPartitionKeyInfo& part_key_info = index_schema.get_partition_key_info();
const common::ObPartitionKeyInfo& subpart_key_info = index_schema.get_subpartition_key_info();
if (!index_schema.is_partitioned_table()) {
// not a partition index, good
} else if (OB_FAIL(check_key_cover_partition_keys(index_schema.is_range_part(), part_key_info, index_schema))) {
LOG_WARN("fail to check key cover", K(ret));
} else if (OB_FAIL(
check_key_cover_partition_keys(index_schema.is_range_subpart(), subpart_key_info, index_schema))) {
LOG_WARN("fail to check key cover", K(ret));
} else {
} // no more to do
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected index type", K(ret), "index_type", crt_idx_stmt->get_create_index_arg().index_type_);
}
} else {
// no need to check
}
return ret;
}
int ObDDLResolver::generate_global_index_schema(ObCreateIndexStmt* crt_idx_stmt)
{
int ret = OB_SUCCESS;
const share::schema::ObTableSchema* table_schema = NULL;
ObTableSchema& index_schema = crt_idx_stmt->get_create_index_arg().index_schema_;
if (OB_UNLIKELY(NULL == crt_idx_stmt)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret));
} else if (!global_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("should not build global schema on a local index", K(ret));
} else if (OB_UNLIKELY(NULL == schema_checker_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("schema checker ptr is null", K(ret));
} else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(),
crt_idx_stmt->get_create_index_arg().database_name_,
crt_idx_stmt->get_create_index_arg().table_name_,
false /* is index table*/,
table_schema))) {
if (OB_TABLE_NOT_EXIST == ret) {
LOG_USER_ERROR(OB_TABLE_NOT_EXIST,
to_cstring(crt_idx_stmt->get_create_index_arg().database_name_),
to_cstring(crt_idx_stmt->get_create_index_arg().table_name_));
LOG_WARN("table not exist",
K(ret),
"database_name",
crt_idx_stmt->get_create_index_arg().database_name_,
"table_name",
crt_idx_stmt->get_create_index_arg().table_name_);
} else {
LOG_WARN("fail to get table schema", K(ret));
}
} else if (OB_UNLIKELY(NULL == table_schema)) {
ret = OB_TABLE_NOT_EXIST;
LOG_USER_ERROR(OB_TABLE_NOT_EXIST,
to_cstring(crt_idx_stmt->get_create_index_arg().database_name_),
to_cstring(crt_idx_stmt->get_create_index_arg().table_name_));
LOG_WARN("table not exist",
K(ret),
"database_name",
crt_idx_stmt->get_create_index_arg().database_name_,
"table_name",
crt_idx_stmt->get_create_index_arg().table_name_);
} else if (!GCONF.enable_sys_table_ddl && !table_schema->is_user_table() && !table_schema->is_tmp_table()) {
ret = OB_ERR_WRONG_OBJECT;
LOG_USER_ERROR(OB_ERR_WRONG_OBJECT,
to_cstring(crt_idx_stmt->get_create_index_arg().database_name_),
to_cstring(crt_idx_stmt->get_create_index_arg().table_name_),
"BASE_TABLE");
ObTableType table_type = table_schema->get_table_type();
LOG_WARN("Not support to create index on non-normal table",
K(ret),
K(table_type),
"arg",
crt_idx_stmt->get_create_index_arg());
} else {
ObArray<ObColumnSchemaV2*> gen_columns;
ObCreateIndexArg& create_index_arg = crt_idx_stmt->get_create_index_arg();
ObCreateIndexArg my_create_index_arg;
index_schema.set_table_type(USER_INDEX);
index_schema.set_index_type(create_index_arg.index_type_);
ObTableSchema new_table_schema;
if (OB_FAIL(new_table_schema.assign(*table_schema))) {
LOG_WARN("fail to assign schema", K(ret));
} else if (OB_FAIL(my_create_index_arg.assign(create_index_arg))) {
LOG_WARN("fail to assign index arg", K(ret));
} else if (OB_FAIL(share::ObIndexBuilderUtil::adjust_expr_index_args(
my_create_index_arg, new_table_schema, gen_columns))) {
LOG_WARN("fail to adjust expr index args", K(ret));
} else if (OB_FAIL(do_generate_global_index_schema(my_create_index_arg, new_table_schema))) {
LOG_WARN("fail to do generate global index schema", K(ret));
} else if (OB_FAIL(index_schema.assign(my_create_index_arg.index_schema_))) {
LOG_WARN("fail to assign schema", K(ret));
}
}
return ret;
}
int ObDDLResolver::do_generate_global_index_schema(
ObCreateIndexArg& create_index_arg, share::schema::ObTableSchema& table_schema)
{
int ret = OB_SUCCESS;
ObTableSchema& index_schema = create_index_arg.index_schema_;
if (OB_FAIL(share::ObIndexBuilderUtil::set_index_table_columns(create_index_arg, table_schema, index_schema))) {
LOG_WARN("fail to set index table columns", K(ret));
} else {
} // no more to do
return ret;
}
int ObDDLResolver::resolve_check_constraint_node(
const ParseNode& cst_node, ObSEArray<ObConstraint, 4>& csts, const share::schema::ObColumnSchemaV2* column_schema)
{
int ret = OB_SUCCESS;
if ((share::is_mysql_mode() && (cst_node.num_child_ != 2)) ||
(share::is_oracle_mode() && (cst_node.num_child_ != 3))) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "the num_child of constraint_node is wrong.", K(cst_node.num_child_), K(ret));
} else {
ObString cst_name;
ParseNode* cst_name_node = cst_node.children_[0];
ParseNode* cst_check_expr_node = cst_node.children_[1];
ParseNode* cst_check_state_node = NULL;
if (share::is_oracle_mode()) {
cst_check_state_node = cst_node.children_[2];
}
if (OB_ISNULL(cst_check_expr_node)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "NULL ptr", K(ret), K(cst_check_expr_node));
} else if (OB_ISNULL(cst_name_node)) {
if (share::is_mysql_mode()) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "NULL ptr", K(ret), K(cst_name_node));
} else if (share::is_oracle_mode()) {
if (OB_FAIL(ObTableSchema::create_cons_name_automatically(
cst_name, table_name_, *allocator_, CONSTRAINT_TYPE_CHECK))) {
SQL_RESV_LOG(WARN, "create cons name automatically failed", K(ret));
}
}
} else {
cst_name.assign_ptr(cst_name_node->str_value_, static_cast<int32_t>(cst_name_node->str_len_));
}
if (OB_SUCC(ret)) {
ObConstraint cst;
if (cst_name.length() > OB_MAX_CONSTRAINT_NAME_LENGTH) {
ret = OB_ERR_TOO_LONG_IDENT;
LOG_WARN("constraint_name length overflow", K(ret), K(cst_name.length()));
} else {
ObTableSchema tmp_table_schema;
ObRawExpr* check_expr = NULL;
if (OB_FAIL(get_table_schema_for_check(tmp_table_schema))) {
LOG_WARN("get table schema failed", K(ret), K(cst_name));
} else {
for (uint64_t i = 0; OB_SUCC(ret) && i < csts.count(); ++i) {
if (csts.at(i).get_constraint_name_str() == cst_name) {
ret = OB_ERR_CONSTRAINT_NAME_DUPLICATE;
LOG_WARN("duplicate check constraint name", K(ret), K(cst_name));
}
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(cst.set_constraint_name(cst_name))) {
LOG_WARN("set constraint name failed", K(ret), K(cst_name));
} else if (OB_FAIL(resolve_check_constraint_expr(
params_, cst_check_expr_node, tmp_table_schema, cst, check_expr, column_schema))) {
LOG_WARN("resolver constraint expr failed", K(ret));
} else {
// resolve constranit_state in oracle mode
if (share::is_oracle_mode()) {
if (OB_FAIL(resolve_check_cst_state_node(cst_check_state_node, cst))) {
SQL_RESV_LOG(WARN, "fail to resolve check cst state node", K(ret));
}
}
if (OB_SUCC(ret)) {
cst.set_constraint_type(CONSTRAINT_TYPE_CHECK);
ret = csts.push_back(cst);
}
}
}
}
}
}
return ret;
}
int ObDDLResolver::resolve_check_cst_state_node(const ParseNode* cst_check_state_node, ObConstraint& cst)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(cst_check_state_node)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "cst_check_state_node is null ptr", K(ret));
} else if (T_CONSTRAINT_STATE != cst_check_state_node->type_) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(
WARN, "cst_check_state_node->type_ must be T_CONSTRAINT_STATE", K(ret), K(cst_check_state_node->type_));
} else if (cst_check_state_node->num_child_ != 4) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "the num_child of cst_check_state_node is wrong.", K(ret), K(cst_check_state_node->num_child_));
} else if (OB_NOT_NULL(cst_check_state_node->children_[1])) {
// in oracle mode: check constraint with using index option, report parser error.
// https://docs.oracle.com/cd/E11882_01/server.112/e41084/clauses002.htm#SQLRF52180
ret = OB_ERR_PARSER_SYNTAX;
SQL_RESV_LOG(WARN, "check constraint can't assign state of using index", K(ret));
} else {
if (OB_NOT_NULL(cst_check_state_node->children_[0])) {
cst.set_rely_flag(T_RELY_CONSTRAINT == cst_check_state_node->children_[0]->type_ ? true : false);
}
if (OB_NOT_NULL(cst_check_state_node->children_[2])) {
cst.set_enable_flag(T_ENABLE_CONSTRAINT == cst_check_state_node->children_[2]->type_ ? true : false);
cst.set_validate_flag(T_ENABLE_CONSTRAINT == cst_check_state_node->children_[2]->type_ ? true : false);
}
if (OB_NOT_NULL(cst_check_state_node->children_[3])) {
cst.set_validate_flag(T_VALIDATE_CONSTRAINT == cst_check_state_node->children_[3]->type_ ? true : false);
}
}
return ret;
}
int ObDDLResolver::resolve_pk_constraint_node(
const ParseNode& pk_cst_node, common::ObString pk_name, ObSEArray<ObConstraint, 4>& csts)
{
int ret = OB_SUCCESS;
ObString cst_name;
if ((T_PRIMARY_KEY != pk_cst_node.type_) && (T_COLUMN_DEFINITION != pk_cst_node.type_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "node type is wrong.", K(ret), K(pk_cst_node.type_));
} else if (T_PRIMARY_KEY == pk_cst_node.type_) {
// case: create table t1(c1 int, primary key(c1));
if (pk_cst_node.num_child_ != 2) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "the num_child of constraint_node is wrong.", K(pk_cst_node.num_child_), K(ret));
} else {
ParseNode* cst_name_node = pk_cst_node.children_[1];
if (OB_ISNULL(cst_name_node)) {
// set default pk constraint name if not specified
if (OB_FAIL(ObTableSchema::create_cons_name_automatically(
cst_name, table_name_, *allocator_, CONSTRAINT_TYPE_PRIMARY_KEY))) {
SQL_RESV_LOG(WARN, "create cons name automatically failed", K(ret));
}
} else {
cst_name.assign_ptr(cst_name_node->str_value_, static_cast<int32_t>(cst_name_node->str_len_));
}
}
} else {
if (NULL == pk_name.ptr()) {
if (OB_FAIL(ObTableSchema::create_cons_name_automatically(
cst_name, table_name_, *allocator_, CONSTRAINT_TYPE_PRIMARY_KEY))) {
SQL_RESV_LOG(WARN, "create cons name automatically failed", K(ret));
}
} else {
cst_name.assign_ptr(pk_name.ptr(), pk_name.length());
}
}
if (OB_SUCC(ret)) {
ObConstraint cst;
if (cst_name.length() > OB_MAX_CONSTRAINT_NAME_LENGTH) {
ret = OB_ERR_TOO_LONG_IDENT;
LOG_WARN("constraint_name length overflow", K(ret), K(cst_name.length()));
} else {
// ObTableSchema tmp_table_schema;
if (csts.end() != std::find_if(csts.begin(), csts.end(), [&cst_name](const ObConstraint& cst) {
return cst_name == cst.get_constraint_name_str();
})) {
ret = OB_ERR_CONSTRAINT_DUPLICATE;
LOG_WARN("duplicate constraint name", K(ret), K(cst_name));
} else if (OB_FAIL(cst.set_constraint_name(cst_name))) {
} else {
cst.set_constraint_type(CONSTRAINT_TYPE_PRIMARY_KEY);
ret = csts.push_back(cst);
}
}
}
return ret;
}
int ObDDLResolver::resolve_check_constraint_expr(ObResolverParams& params, const ParseNode* node,
ObTableSchema& table_schema, ObConstraint& constraint, ObRawExpr*& check_expr,
const share::schema::ObColumnSchemaV2* column_schema)
{
int ret = OB_SUCCESS;
check_expr = NULL;
if (OB_ISNULL(node)) {
ret = OB_NOT_INIT;
LOG_WARN("NULL ptr", K(node));
} else {
if (OB_FAIL(ObResolverUtils::resolve_check_constraint_expr(
params, node, table_schema, constraint, check_expr, column_schema))) {
LOG_WARN("resolve check constraint expr failed", K(ret));
} else if (OB_ISNULL(check_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("check_expr is null", K(ret));
}
}
return ret;
}
int ObDDLResolver::check_uniq_allow(ObResolverParams& params, ObTableSchema& table_schema, ObCreateIndexArg& index_arg,
ObRawExpr* part_func_expr, ObIArray<ObRawExpr*>& constraint_exprs, bool& allow)
{
int ret = OB_SUCCESS;
allow = false;
ObColumnRefRawExpr* part_col_expr = NULL;
if (!part_func_expr->is_column_ref_expr()) {
allow = false;
} else if (FALSE_IT(part_col_expr = static_cast<ObColumnRefRawExpr*>(part_func_expr))) {
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < index_arg.index_columns_.count() && !allow; ++i) {
const ObString& index_col_name = index_arg.index_columns_.at(i).column_name_;
const ObString& part_col_name = part_col_expr->get_column_name();
if (ObCharset::case_insensitive_equal(index_col_name, part_col_name)) {
allow = true;
} else {
// concern as base-column
for (int64_t j = 0; OB_SUCC(ret) && j < constraint_exprs.count() && !allow; ++j) {
ObOpRawExpr* check_expr = static_cast<ObOpRawExpr*>(constraint_exprs.at(j));
ObRawExpr* child_exprs[2] = {check_expr->get_param_expr(0), check_expr->get_param_expr(1)};
for (int64_t k = 0; OB_SUCC(ret) && k < 2 && !allow; ++k) {
if (child_exprs[k]->is_column_ref_expr()) {
ObColumnRefRawExpr* col_expr = static_cast<ObColumnRefRawExpr*>(child_exprs[k]);
if (ObCharset::case_insensitive_equal(part_col_name, col_expr->get_column_name())) {
ObColumnRefRawExpr* cmp_col_expr = NULL;
if (!child_exprs[1 - k]->is_column_ref_expr()) {
cmp_col_expr = static_cast<ObColumnRefRawExpr*>(child_exprs[1 - k]->get_param_expr(0));
} else {
cmp_col_expr = static_cast<ObColumnRefRawExpr*>(child_exprs[1 - k]);
}
if (ObCharset::case_insensitive_equal(cmp_col_expr->get_column_name(), index_col_name)) {
allow = true;
}
}
}
}
}
// check gen column
if (OB_SUCC(ret) && !allow) {
ObColumnSchemaV2* column_schema = NULL;
if (OB_ISNULL(column_schema = table_schema.get_column_schema(part_col_expr->get_column_id()))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Failed to get column schema", K(ret), K(part_col_expr->get_column_id()));
} else if (column_schema->is_generated_column()) {
ObString col_def;
ObRawExpr* gen_expr = NULL;
if (OB_FAIL(column_schema->get_orig_default_value().get_string(col_def))) {
LOG_WARN("get generated column definition failed", K(ret));
} else if (OB_FAIL(ObResolverUtils::resolve_generated_column_expr(
params, col_def, table_schema, *column_schema, gen_expr))) {
LOG_WARN("resolve generated column expr failed", K(ret));
} else {
ObString depend_part_col_name;
bool is_expect = true;
// check is substring or not
if (OB_ISNULL(gen_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret));
} else if (T_FUN_SYS_SUBSTR != gen_expr->get_expr_type()) {
is_expect = false;
} else {
ObSysFunRawExpr* sys_expr = static_cast<ObSysFunRawExpr*>(gen_expr);
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()) {
is_expect = false;
} else if (0 != j && !param_expr->is_const_expr()) {
is_expect = false;
}
}
if (OB_SUCC(ret) && is_expect) {
depend_part_col_name =
static_cast<ObColumnRefRawExpr*>(sys_expr->get_param_expr(0))->get_column_name();
}
if (OB_SUCC(ret) && !is_expect) {
continue;
}
}
for (int64_t j = 0; OB_SUCC(ret) && j < constraint_exprs.count() && !allow; ++j) {
ObOpRawExpr* check_expr = static_cast<ObOpRawExpr*>(constraint_exprs.at(j));
ObRawExpr* child_exprs[2] = {check_expr->get_param_expr(0), check_expr->get_param_expr(1)};
ObColumnRefRawExpr* col_exprs[2] = {NULL, NULL};
bool gen_expr_exist = false;
bool all_col = true;
for (int64_t k = 0; OB_SUCC(ret) && k < 2; ++k) {
if (child_exprs[k]->is_column_ref_expr()) {
col_exprs[k] = static_cast<ObColumnRefRawExpr*>(child_exprs[k]);
} else {
all_col = false;
col_exprs[k] = static_cast<ObColumnRefRawExpr*>(child_exprs[k]->get_param_expr(0));
if (!gen_expr_exist) {
ret = check_same_substr_expr(*child_exprs[k], *gen_expr, gen_expr_exist);
}
}
}
if (OB_SUCC(ret)) {
if (all_col || gen_expr_exist) {
if (ObCharset::case_insensitive_equal(col_exprs[0]->get_column_name(), index_col_name) &&
ObCharset::case_insensitive_equal(col_exprs[1]->get_column_name(), depend_part_col_name)) {
allow = true;
} else if (ObCharset::case_insensitive_equal(col_exprs[1]->get_column_name(), index_col_name) &&
ObCharset::case_insensitive_equal(
col_exprs[0]->get_column_name(), depend_part_col_name)) {
allow = true;
}
}
}
}
}
}
}
}
}
}
return ret;
}
int ObDDLResolver::check_same_substr_expr(ObRawExpr& left, ObRawExpr& right, bool& same)
{
int ret = OB_SUCCESS;
same = true;
if (left.get_expr_type() != T_FUN_SYS_SUBSTR || right.get_expr_type() != T_FUN_SYS_SUBSTR) {
same = false;
} else {
ObSysFunRawExpr& sys_left = static_cast<ObSysFunRawExpr&>(left);
ObSysFunRawExpr& sys_right = static_cast<ObSysFunRawExpr&>(right);
if (sys_left.get_param_count() != sys_right.get_param_count()) {
same = false;
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < sys_left.get_param_count() && same; ++i) {
ObRawExpr* param_left = sys_left.get_param_expr(i);
ObRawExpr* param_right = sys_right.get_param_expr(i);
if (0 == i) {
if (!param_left->is_column_ref_expr() || !param_right->is_column_ref_expr()) {
same = false;
} else {
ObColumnRefRawExpr* col_left = static_cast<ObColumnRefRawExpr*>(param_left);
ObColumnRefRawExpr* col_right = static_cast<ObColumnRefRawExpr*>(param_right);
if (!ObCharset::case_insensitive_equal(col_left->get_column_name(), col_right->get_column_name())) {
same = false;
}
}
} else {
if (!param_left->is_const_expr() || !param_right->is_const_expr()) {
same = false;
} else if (!param_left->same_as(*param_right)) {
same = false;
}
}
}
}
}
return ret;
}
int ObDDLResolver::check_uniq_allow(ObTableSchema& table_schema, ObCreateIndexArg& index_arg, bool& allow)
{
int ret = OB_SUCCESS;
allow = false;
if (table_schema.get_part_level() == PARTITION_LEVEL_ONE && table_schema.get_part_option().is_list_part()) {
ObArenaAllocator allocator(ObModIds::OB_TEMP_VARIABLES);
ObResolverParams params;
ObRawExprFactory expr_factory(allocator);
ObSQLSessionInfo empty_session;
params.expr_factory_ = &expr_factory;
params.allocator_ = &allocator;
params.session_info_ = &empty_session;
if (OB_FAIL(empty_session.init(0, 0, 0, &allocator))) {
LOG_WARN("init empty session failed", K(ret));
} else if (OB_FAIL(empty_session.load_default_sys_variable(false, false))) {
LOG_WARN("session load default system variable failed", K(ret));
} else {
const share::schema::ObPartitionFuncType part_func_type = table_schema.get_part_option().get_part_func_type();
const ParseNode* node = NULL;
common::ObSEArray<common::ObString, 8> part_keys;
common::ObSEArray<ObRawExpr*, 8> part_func_exprs;
if (OB_FAIL(ObRawExprUtils::parse_expr_node_from_str(
table_schema.get_part_option().get_part_func_expr_str(), *params.allocator_, node))) {
LOG_WARN("parse expr node from string failed", K(ret));
} else if (OB_FAIL(resolve_part_func(params, node, part_func_type, table_schema, part_func_exprs, part_keys))) {
SQL_RESV_LOG(WARN, "resolve part func failed", K(ret));
}
if (OB_SUCC(ret) && part_func_exprs.count() == 1) {
ObSEArray<ObRawExpr*, 8> check_exprs;
for (ObTableSchema::const_constraint_iterator iter = table_schema.constraint_begin();
OB_SUCC(ret) && iter != table_schema.constraint_end();
iter++) {
ObConstraint cst;
ObRawExpr* check_expr = NULL;
if ((*iter)->get_constraint_type() != CONSTRAINT_TYPE_CHECK) {
continue;
} else if (OB_FAIL(ObRawExprUtils::parse_bool_expr_node_from_str(
(*iter)->get_check_expr_str(), *params.allocator_, node))) {
LOG_WARN("parse expr node from string failed", K(ret));
} else if (OB_FAIL(resolve_check_constraint_expr(params, node, table_schema, cst, check_expr))) {
LOG_WARN("resolver constraint expr failed", K(ret));
} else {
ret = check_exprs.push_back(check_expr);
}
}
bool tmp_allow = false;
if (OB_FAIL(ret)) {
} else if (OB_FAIL(check_uniq_allow(
params, table_schema, index_arg, part_func_exprs.at(0), check_exprs, tmp_allow))) {
LOG_WARN("check_uniq_allowe failed", K(ret));
} else if (tmp_allow) {
allow = tmp_allow;
}
}
}
}
return ret;
}
int ObDDLResolver::resolve_split_partition_range_element(const ParseNode* node,
const share::schema::ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
common::ObIArray<ObRawExpr*>& range_value_exprs, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(node) || T_EXPR_LIST != node->type_) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid_argument", K(ret), "type", node->type_);
} else if (!in_tablegroup) {
if (node->num_child_ != part_func_exprs.count()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid_argument", K(ret), "node num", node->num_child_, "function num", part_func_exprs.count());
}
}
ObString part_name;
for (int i = 0; OB_SUCC(ret) && i < node->num_child_; ++i) {
if (OB_ISNULL(node->children_[i])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null", K(ret), K(i), "node", node->children_[i]);
} else if (T_MAXVALUE == node->children_[i]->type_) {
ObRawExpr* maxvalue_expr = NULL;
ObConstRawExpr* c_expr = NULL;
c_expr = (ObConstRawExpr*)allocator_->alloc(sizeof(ObConstRawExpr));
if (OB_ISNULL(c_expr)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to alloc raw expr", K(ret), K(c_expr));
} else {
c_expr = new (c_expr) ObConstRawExpr();
maxvalue_expr = c_expr;
maxvalue_expr->set_data_type(common::ObMaxType);
if (OB_FAIL(range_value_exprs.push_back(maxvalue_expr))) {
LOG_WARN("array push back fail", K(ret));
}
}
} else if (T_NULL == node->children_[i]->type_) {
ret = OB_EER_NULL_IN_VALUES_LESS_THAN;
LOG_WARN("null value is not allowed in less than", K(ret));
} else if (T_EXPR_LIST != node->children_[i]->type_) {
ObRawExpr* part_value_expr = NULL;
ObRawExpr* part_func_expr = NULL;
if (!in_tablegroup) {
if (OB_FAIL(part_func_exprs.at(i, part_func_expr))) {
LOG_WARN("get part expr failed", K(ret), K(i), "size", part_func_exprs.count());
} else if (OB_ISNULL(part_func_expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("part func expr is invalid", K(ret), K(i));
} 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("failed to resolve at values", K(ret));
}
} else {
if (OB_FAIL(ObResolverUtils::resolve_partition_range_value_expr(
params_, *(node->children_[i]), part_name, part_type, part_value_expr, in_tablegroup))) {
LOG_WARN("failed to resolve at values", K(ret));
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(range_value_exprs.push_back(part_value_expr))) {
LOG_WARN("failed to push back raw_expr", K(ret), K(part_value_expr));
}
}
} // end for process t_expr_list
return ret;
}
int ObDDLResolver::resolve_split_partition_list_value(const ParseNode* node,
const share::schema::ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
ObDDLStmt::array_t& list_value_exprs, int64_t& expr_num, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
ObString part_name;
ObOpRawExpr* row_expr = NULL;
if (OB_ISNULL(node) || OB_ISNULL(params_.expr_factory_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(node), K(params_.expr_factory_));
} else if (T_EXPR_LIST != node->type_ && T_DEFAULT != node->type_) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument node type", K(ret), "node type", node->type_);
} else if (OB_FAIL(params_.expr_factory_->create_raw_expr(T_OP_ROW, row_expr))) {
LOG_WARN("failed to create raw expr", K(ret));
} else if (OB_ISNULL(row_expr)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allcoate memory", K(ret));
} else if (T_DEFAULT == node->type_) {
// replace default value with max
ObRawExpr* maxvalue_expr = NULL;
ObConstRawExpr* c_expr = NULL;
c_expr = (ObConstRawExpr*)allocator_->alloc(sizeof(ObConstRawExpr));
if (OB_ISNULL(c_expr)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
} else {
c_expr = new (c_expr) ObConstRawExpr();
maxvalue_expr = c_expr;
maxvalue_expr->set_data_type(common::ObMaxType);
ObDDLStmt::array_t part_value_expr_array;
if (OB_FAIL(row_expr->add_param_expr(maxvalue_expr))) {
LOG_WARN("failed to add param expr", K(ret));
} else if (OB_FAIL(list_value_exprs.push_back(row_expr))) {
LOG_WARN("array push back fail", K(ret));
}
}
} else {
ObSEArray<ObRawExpr*, 16> part_value_exprs;
bool is_all_expr_list = false;
if (node->num_child_ > 0) {
is_all_expr_list = (node->children_[0]->type_ == T_EXPR_LIST);
}
for (int64_t j = 0; OB_SUCC(ret) && j < node->num_child_; j++) {
part_value_exprs.reset();
if (OB_ISNULL(node->children_[j])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null", K(ret));
} else if ((is_all_expr_list && node->children_[j]->type_ != T_EXPR_LIST) ||
(!is_all_expr_list && node->children_[j]->type_ == T_EXPR_LIST)) {
ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
} else if (!in_tablegroup &&
OB_FAIL(ObResolverUtils::resolve_partition_list_value_expr(
params_, *(node->children_[j]), part_name, part_type, part_func_exprs, part_value_exprs))) {
LOG_WARN("resolve partition expr failed", K(ret));
} else if (in_tablegroup && OB_FAIL(ObResolverUtils::resolve_partition_list_value_expr(params_,
*(node->children_[j]),
part_name,
part_type,
expr_num,
part_value_exprs,
in_tablegroup))) {
LOG_WARN("resolve partition expr failed", K(ret));
}
for (int64_t k = 0; OB_SUCC(ret) && k < part_value_exprs.count(); k++) {
if (OB_FAIL(row_expr->add_param_expr(part_value_exprs.at(k)))) {
LOG_WARN("failed to add param expr", K(ret));
}
} // end for
} // end for
if (OB_FAIL(ret)) {
} else if (part_func_exprs.count() > 1 && !is_all_expr_list) {
if (row_expr->get_param_count() != part_func_exprs.count()) {
ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
}
}
if (OB_FAIL(ret)) {
} else if (OB_FAIL(list_value_exprs.push_back(row_expr))) {
LOG_WARN("array push back fail", K(ret));
}
}
return ret;
}
int ObDDLResolver::check_split_type_valid(
const ParseNode* split_node, const share::schema::ObPartitionFuncType part_type)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(split_node) || T_SPLIT_ACTION != split_node->type_ ||
OB_ISNULL(split_node->children_[SPLIT_PARTITION_TYPE_NODE]) || PARTITION_FUNC_TYPE_MAX == part_type) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("node type error or partition type node is null",
K(ret),
"node_type",
split_node->type_,
"split_partition_type",
split_node->children_[SPLIT_PARTITION_TYPE_NODE],
K(part_type));
} else if (share::schema::is_list_part(part_type) &&
T_SPLIT_LIST != split_node->children_[SPLIT_PARTITION_TYPE_NODE]->type_) {
ret = OB_ERR_UNEXPECTED;
LOG_USER_ERROR(OB_ERR_UNEXPECTED, "VALUES LESS THAN or AT clause cannot be used with List partition");
LOG_WARN("at clause cannot be used with list partition",
K(ret),
"node_type",
split_node->children_[SPLIT_PARTITION_TYPE_NODE]->type_);
} else if (share::schema::is_range_part(part_type) &&
T_SPLIT_RANGE != split_node->children_[SPLIT_PARTITION_TYPE_NODE]->type_) {
ret = OB_ERR_UNEXPECTED;
LOG_USER_ERROR(OB_ERR_UNEXPECTED, "expecting VALUES LESS THAN or AT clause");
LOG_WARN("values clause cannot be used with range partitioned",
K(ret),
"node_type",
split_node->children_[SPLIT_PARTITION_TYPE_NODE]->type_);
}
return ret;
}
int ObDDLResolver::generate_index_name(
ObString& index_name, IndexNameSet& current_index_name_set, const common::ObString& first_col_name)
{
int ret = OB_SUCCESS;
// inspect whether first_column_name is exist
ObIndexNameHashWrapper index_key(first_col_name);
if (OB_ISNULL(allocator_)) {
ret = OB_NOT_INIT;
SQL_RESV_LOG(WARN, "allocator is null.", K(ret));
} else if (OB_HASH_EXIST != current_index_name_set.exist_refactored(index_key)) {
if (OB_FAIL(ob_write_string(*allocator_, first_col_name, index_name))) {
SQL_RESV_LOG(WARN, "failed to set index name to first column name", K(ret));
}
} else {
char buffer[number::ObNumber::MAX_PRINTABLE_SIZE];
ObString str;
bool b_flag = false;
ObIndexNameHashWrapper tmp_key;
for (int32_t i = 2; OB_SUCC(ret) && !b_flag; ++i) {
if (snprintf(buffer, sizeof(buffer), "%.*s_%d", first_col_name.length(), first_col_name.ptr(), i) < 0) {
ret = OB_SIZE_OVERFLOW;
SQL_RESV_LOG(WARN, "failed to generate buffer", K(first_col_name), K(ret));
} else if (OB_FAIL(ob_write_string(*allocator_, ObString::make_string(buffer), str))) {
SQL_RESV_LOG(WARN, "Can not malloc space for index name");
} else {
tmp_key.set_name(str);
if (OB_HASH_EXIST != current_index_name_set.exist_refactored(tmp_key)) {
b_flag = true;
}
}
}
index_name.assign_ptr(str.ptr(), str.length());
}
return ret;
}
int ObDDLResolver::resolve_foreign_key(const ParseNode* node, ObArray<int>& node_position_list)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(node)) {
// do nothing, create table t as select ... will come here
} else if (T_TABLE_ELEMENT_LIST != node->type_) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(node->type_));
} else if (OB_ISNULL(stmt_)) {
ret = OB_NOT_INIT;
SQL_RESV_LOG(WARN, "stmt_ is null", K(ret));
} else if (OB_ISNULL(node->children_)) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(node->children_));
} else {
ObCreateTableStmt* create_table_stmt = static_cast<ObCreateTableStmt*>(stmt_);
for (int64_t i = 0; OB_SUCC(ret) && i < node_position_list.size(); ++i) {
int child_pos = node_position_list.at(i);
ObCreateForeignKeyArg foreign_key_arg;
if (!(0 <= child_pos && child_pos < node->num_child_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "node pos out of range", K(ret), K(child_pos), K(node->num_child_));
} else if (OB_FAIL(resolve_foreign_key_node(node->children_[child_pos], foreign_key_arg, false))) {
SQL_RESV_LOG(WARN, "failed to resolve foreign key node", K(ret), K(child_pos));
} else if (OB_FAIL(create_table_stmt->get_foreign_key_arg_list().push_back(foreign_key_arg))) {
SQL_RESV_LOG(WARN, "failed to push back foreign key arg", K(ret));
}
}
if (OB_SUCC(ret) && share::is_oracle_mode() &&
OB_FAIL(ObResolverUtils::check_dup_foreign_keys_exist(create_table_stmt->get_foreign_key_arg_list()))) {
SQL_RESV_LOG(WARN, "failed to check dup foreign keys exist", K(ret));
}
current_foreign_key_name_set_.reset();
}
return ret;
}
int ObDDLResolver::resolve_foreign_key_node(
const ParseNode* node, obrpc::ObCreateForeignKeyArg& arg, bool is_alter_table, const ObColumnSchemaV2* column)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(node)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "node is null", K(ret));
} else if (!is_oracle_mode()) {
// mysql mode
if (T_FOREIGN_KEY != node->type_ || 7 != node->num_child_ || OB_ISNULL(node->children_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(node->type_), K(node->num_child_), K(node->children_));
} else {
ParseNode* child_columns = node->children_[0];
ParseNode* parent_table = node->children_[1];
ParseNode* parent_columns = node->children_[2];
ParseNode* reference_options = node->children_[3];
ParseNode* constraint_name = node->children_[4];
ParseNode* foreign_key_name = node->children_[5];
UNUSED(foreign_key_name);
ParseNode* match_options = node->children_[6];
if (OB_FAIL(resolve_table_relation_node(parent_table, arg.parent_table_, arg.parent_database_))) {
LOG_WARN("failed to resolve foreign key parent table", K(ret));
} else if (OB_FAIL(resolve_foreign_key_columns(child_columns, arg.child_columns_))) {
LOG_WARN("failed to resolve foreign key child columns", K(ret));
} else if (OB_FAIL(resolve_foreign_key_columns(parent_columns, arg.parent_columns_))) {
LOG_WARN("failed to resolve foreign key parent columns", K(ret));
} else if (OB_FAIL(resolve_foreign_key_options(reference_options, arg.update_action_, arg.delete_action_))) {
LOG_WARN("failed to resolve foreign key options", K(ret));
} else if (OB_FAIL(resolve_foreign_key_name(constraint_name, arg.foreign_key_name_))) {
LOG_WARN("failed to resolve foreign key name", K(ret));
} else if (OB_FAIL(check_foreign_key_reference(arg, is_alter_table, NULL))) {
LOG_WARN("failed to check reference columns", K(ret));
} else if (OB_FAIL(resolve_match_options(match_options))) {
LOG_WARN("failed to resolve match options", K(ret));
}
}
} else {
// oracle mode
if (NULL == column) { // table level foreign key in oracle mode
if (T_FOREIGN_KEY != node->type_ || 4 != node->num_child_ || OB_ISNULL(node->children_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(node->type_), K(node->num_child_), K(node->children_));
} else {
ParseNode* constraint_name = node->children_[0];
ParseNode* child_columns = node->children_[1];
ParseNode* references_clause_node = node->children_[2];
ParseNode* fk_enable_state_node = node->children_[3];
ParseNode* parent_table = nullptr;
ParseNode* parent_columns = nullptr;
ParseNode* reference_options = nullptr;
if (OB_ISNULL(references_clause_node)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to resolve references clause, node is null", K(ret));
} else {
// resolve references_clause
if (T_REFERENCES_CLAUSE != references_clause_node->type_ || 3 != references_clause_node->num_child_ ||
OB_ISNULL(references_clause_node->children_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN,
"invalid argument",
K(ret),
K(references_clause_node->type_),
K(references_clause_node->num_child_),
K(references_clause_node->children_));
} else {
parent_table = references_clause_node->children_[0];
parent_columns = references_clause_node->children_[1];
reference_options = references_clause_node->children_[2];
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(resolve_table_relation_node(parent_table, arg.parent_table_, arg.parent_database_))) {
LOG_WARN("failed to resolve foreign key parent table", K(ret));
} else if (OB_FAIL(resolve_foreign_key_columns(child_columns, arg.child_columns_))) {
LOG_WARN("failed to resolve foreign key child columns", K(ret));
} else if (OB_FAIL(resolve_fk_referenced_columns_oracle(
parent_columns, arg, is_alter_table, arg.parent_columns_))) {
LOG_WARN("failed to resolve foreign key parent columns in oracle mode", K(ret));
} else if (OB_FAIL(resolve_foreign_key_option(reference_options, arg.update_action_, arg.delete_action_))) {
LOG_WARN("failed to resolve foreign key options", K(ret));
} else if (OB_FAIL(resolve_foreign_key_name(constraint_name, arg.foreign_key_name_))) {
LOG_WARN("failed to resolve foreign key name", K(ret));
} else if (OB_FAIL(check_foreign_key_reference(arg, is_alter_table, NULL))) {
LOG_WARN("failed to check reference columns", K(ret));
} else if (OB_FAIL(resolve_foreign_key_state(fk_enable_state_node, arg))) {
LOG_WARN("failed to resolve foreign key enable_state", K(ret));
}
}
}
} else { // column level foreign key in oracle mode
if (T_FOREIGN_KEY != node->type_ || 3 != node->num_child_ || OB_ISNULL(node->children_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(node->type_), K(node->num_child_), K(node->children_));
} else {
ParseNode* constraint_name = node->children_[0];
ParseNode* references_clause_node = node->children_[1];
ParseNode* fk_enable_state_node = node->children_[2];
ParseNode* parent_table = nullptr;
ParseNode* parent_columns = nullptr;
ParseNode* reference_options = nullptr;
if (OB_ISNULL(references_clause_node)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to resolve references clause, node is null", K(ret));
} else {
// resolve references_clause
if (T_REFERENCES_CLAUSE != references_clause_node->type_ || 3 != references_clause_node->num_child_ ||
OB_ISNULL(references_clause_node->children_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN,
"invalid argument",
K(ret),
K(references_clause_node->type_),
K(references_clause_node->num_child_),
K(references_clause_node->children_));
} else {
parent_table = references_clause_node->children_[0];
parent_columns = references_clause_node->children_[1];
reference_options = references_clause_node->children_[2];
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(resolve_table_relation_node(parent_table, arg.parent_table_, arg.parent_database_))) {
LOG_WARN("failed to resolve foreign key parent table", K(ret));
} else if (OB_FAIL(arg.child_columns_.push_back(
ObString(column->get_column_name_str().length(), column->get_column_name_str().ptr())))) {
LOG_WARN("failed to push back column name", K(ret));
} else if (OB_FAIL(resolve_fk_referenced_columns_oracle(
parent_columns, arg, is_alter_table, arg.parent_columns_))) {
LOG_WARN("failed to resolve foreign key parent columns", K(ret));
} else if (OB_FAIL(resolve_foreign_key_option(reference_options, arg.update_action_, arg.delete_action_))) {
LOG_WARN("failed to resolve foreign key options", K(ret));
} else if (OB_FAIL(resolve_foreign_key_name(constraint_name, arg.foreign_key_name_))) {
LOG_WARN("failed to resolve foreign key name", K(ret));
} else if (OB_FAIL(check_foreign_key_reference(arg, is_alter_table, column))) {
LOG_WARN("failed to check reference columns", K(ret));
} else if (OB_FAIL(resolve_foreign_key_state(fk_enable_state_node, arg))) {
LOG_WARN("failed to resolve foreign key enable_state", K(ret));
}
}
}
}
} // end oracle mode
return ret;
}
int ObDDLResolver::resolve_foreign_key_columns(const ParseNode* node, ObIArray<ObString>& columns)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(node)) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "node is null", K(ret));
} else if (OB_ISNULL(node->children_)) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(node->type_), K(node->num_child_), K(node->children_));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < node->num_child_; i++) {
ParseNode* column = node->children_[i];
if (OB_ISNULL(column)) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "child is null", K(ret));
} else if (OB_ISNULL(column->str_value_)) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(column->type_), K(column->str_value_));
} else if (OB_FAIL(columns.push_back(ObString(column->str_len_, column->str_value_)))) {
LOG_WARN("failed to push back column name", K(ret), K(column->str_value_));
}
}
}
return ret;
}
int ObDDLResolver::resolve_fk_referenced_columns_oracle(
const ParseNode* node, const obrpc::ObCreateForeignKeyArg& arg, bool is_alter_table, ObIArray<ObString>& columns)
{
int ret = OB_SUCCESS;
if (share::is_oracle_mode() && OB_ISNULL(node)) {
// oracle mode: ref column can be default, will auto ref parent table's pk column
const ObTableSchema* parent_table_schema = NULL;
if (0 == arg.parent_table_.case_compare(table_name_) && 0 == arg.parent_database_.case_compare(database_name_) &&
!is_alter_table) {
// create table with self-ref foreign key
if (OB_ISNULL(static_cast<ObCreateTableStmt*>(stmt_))) {
ret = OB_NOT_INIT;
SQL_RESV_LOG(WARN, "stmt_ is null.", K(ret));
} else {
parent_table_schema = &static_cast<ObCreateTableStmt*>(stmt_)->get_create_table_arg().schema_;
if (OB_ISNULL(parent_table_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("parent table schema is null", K(ret));
}
}
} else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(),
arg.parent_database_,
arg.parent_table_,
false,
parent_table_schema))) {
LOG_WARN("table is not exist", K(ret), K(arg.parent_database_), K(arg.parent_table_));
} else if (OB_ISNULL(parent_table_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("parent table schema is null", K(ret));
}
if (OB_SUCC(ret)) {
const ObRowkeyInfo& rowkey_info = parent_table_schema->get_rowkey_info();
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(columns.push_back(col_schema->get_column_name()))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("push back index column failed", K(ret));
}
}
if (OB_SUCC(ret) && (0 == columns.count())) {
ret = OB_ERR_REFERENCED_TABLE_HAS_NO_PK;
LOG_WARN("referenced table does not have a primary key", K(ret), KPC(parent_table_schema));
}
}
} else if (OB_FAIL(resolve_foreign_key_columns(node, columns))) {
LOG_WARN("failed to resolve foreign key columns", K(ret));
}
return ret;
}
int ObDDLResolver::resolve_foreign_key_options(
const ParseNode* node, ObReferenceAction& update_action, ObReferenceAction& delete_action)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(node)) {
// nothing.
} else if (T_REFERENCE_OPTION_LIST != node->type_ || node->num_child_ > 2) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(node->type_), K(node->num_child_));
} else if (NULL != node->children_) {
update_action = ACTION_INVALID;
delete_action = ACTION_INVALID;
ParseNode* option_node = NULL;
for (int64_t i = 0; OB_SUCC(ret) && i < node->num_child_; i++) {
option_node = node->children_[i];
ObReferenceAction action = ACTION_INVALID;
if (OB_ISNULL(option_node)) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "option node is null", K(ret), K(i));
} else {
switch (option_node->int32_values_[1]) {
case T_RESTRICT:
action = ACTION_RESTRICT;
break;
case T_CASCADE:
action = ACTION_CASCADE;
break;
case T_SET_NULL:
// action = ACTION_SET_NULL;
ret = OB_NOT_SUPPORTED;
LOG_USER_ERROR(OB_NOT_SUPPORTED, "create foreign key with set null option");
break;
case T_NO_ACTION:
action = ACTION_NO_ACTION;
break;
case T_SET_DEFAULT:
ret = OB_ERR_CANNOT_ADD_FOREIGN;
SQL_RESV_LOG(WARN,
"Cannot add foreign key constraint, because the key word of action is ACTION_SET_DEFAULT",
K(ret),
K(node->int32_values_[1]));
break;
default:
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid reference option", K(ret), K(option_node->int32_values_[1]));
break;
}
}
if (OB_SUCC(ret)) {
switch (option_node->int32_values_[0]) {
case T_UPDATE:
if (ACTION_INVALID != update_action) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "mutli update option", K(ret));
} else {
update_action = action;
}
break;
case T_DELETE:
if (ACTION_INVALID != delete_action) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "mutli delete option", K(ret));
} else {
delete_action = action;
}
break;
default:
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid reference option", K(ret), K(option_node->int32_values_[0]));
break;
}
}
}
}
if (OB_SUCC(ret)) {
if (ACTION_INVALID == update_action) {
update_action = ACTION_RESTRICT;
}
if (ACTION_INVALID == delete_action) {
delete_action = ACTION_RESTRICT;
}
}
return ret;
}
// for oracle mode
int ObDDLResolver::resolve_foreign_key_option(const ParseNode* option_node,
share::schema::ObReferenceAction& update_action, share::schema::ObReferenceAction& delete_action)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(option_node)) {
// do nothing.
} else if (T_REFERENCE_OPTION != option_node->type_) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(option_node->type_));
} else {
ObReferenceAction action = ACTION_INVALID;
switch (option_node->int32_values_[1]) {
case T_CASCADE:
action = ACTION_CASCADE;
break;
case T_SET_NULL:
// action = ACTION_SET_NULL;
ret = OB_NOT_SUPPORTED;
LOG_USER_ERROR(OB_NOT_SUPPORTED, "create foreign key with set null option");
break;
default:
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid reference option", K(ret), K(option_node->int32_values_[1]));
break;
}
if (OB_SUCC(ret)) {
switch (option_node->int32_values_[0]) {
case T_DELETE:
delete_action = action;
break;
default:
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid reference option", K(ret), K(option_node->int32_values_[0]));
break;
}
}
}
// default value is ACTION_RESTRICT
if (OB_SUCC(ret)) {
if (ACTION_INVALID == update_action) {
update_action = ACTION_RESTRICT;
}
if (ACTION_INVALID == delete_action) {
delete_action = ACTION_RESTRICT;
}
}
return ret;
}
int ObDDLResolver::resolve_foreign_key_name(const ParseNode* constraint_node, ObString& foreign_key_name)
{
int ret = OB_SUCCESS;
foreign_key_name.reset();
if (OB_NOT_NULL(constraint_node)) {
if (!is_oracle_mode()) {
// mysql mode
const ParseNode* constraint_name = NULL;
if (T_CHECK_CONSTRAINT != constraint_node->type_ || 1 != constraint_node->num_child_ ||
OB_ISNULL(constraint_node->children_)) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN,
"invalid argument",
K(ret),
K(constraint_node->type_),
K(constraint_node->num_child_),
KP(constraint_node->children_));
} else if (OB_NOT_NULL(constraint_name = constraint_node->children_[0])) {
foreign_key_name.assign_ptr(constraint_name->str_value_, static_cast<int32_t>(constraint_name->str_len_));
// check if fk name duplicated in create_table
ObForeignKeyNameHashWrapper fk_key(foreign_key_name);
if (OB_HASH_EXIST == (ret = current_foreign_key_name_set_.exist_refactored(fk_key))) {
SQL_RESV_LOG(WARN, "duplicate fk name", K(ret), K(foreign_key_name));
ret = OB_ERR_CANNOT_ADD_FOREIGN;
} else {
ret = OB_SUCCESS;
if (OB_FAIL(current_foreign_key_name_set_.set_refactored(fk_key))) {
SQL_RESV_LOG(WARN, "set foreign key name to hash set failed", K(ret), K(foreign_key_name));
}
}
} else if (OB_FAIL(create_fk_cons_name_automatically(foreign_key_name))) {
SQL_RESV_LOG(WARN, "create cons name automatically failed", K(ret));
}
} else {
// oracle mode
foreign_key_name.assign_ptr(constraint_node->str_value_, static_cast<int32_t>(constraint_node->str_len_));
ObForeignKeyNameHashWrapper fk_key(foreign_key_name);
if (OB_HASH_EXIST == (ret = current_foreign_key_name_set_.exist_refactored(fk_key))) {
SQL_RESV_LOG(WARN, "duplicate fk name", K(ret), K(foreign_key_name));
ret = OB_ERR_CANNOT_ADD_FOREIGN;
} else {
ret = OB_SUCCESS;
if (OB_FAIL(current_foreign_key_name_set_.set_refactored(fk_key))) {
SQL_RESV_LOG(WARN, "set foreign key name to hash set failed", K(ret), K(foreign_key_name));
}
}
}
} else if (OB_FAIL(create_fk_cons_name_automatically(foreign_key_name))) {
SQL_RESV_LOG(WARN, "create cons name automatically failed", K(ret));
}
return ret;
}
int ObDDLResolver::resolve_foreign_key_state(const ParseNode* fk_state_node, obrpc::ObCreateForeignKeyArg& arg)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(fk_state_node)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "cst_check_state_node is null ptr", K(ret));
} else if (T_CONSTRAINT_STATE != fk_state_node->type_) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "fk_state_node->type_ must be T_CONSTRAINT_STATE", K(ret), K(fk_state_node->type_));
} else if (fk_state_node->num_child_ != 4) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "the num_child of cst_check_state_node is wrong.", K(ret), K(fk_state_node->num_child_));
} else if (OB_NOT_NULL(fk_state_node->children_[1])) {
// https://docs.oracle.com/cd/E11882_01/server.112/e41084/clauses002.htm#SQLRF52180
ret = OB_ERR_PARSER_SYNTAX;
SQL_RESV_LOG(WARN, "foreign key can't assign state of using index", K(ret));
} else {
if (OB_NOT_NULL(fk_state_node->children_[0])) {
arg.rely_flag_ = (T_RELY_CONSTRAINT == fk_state_node->children_[0]->type_ ? true : false);
}
if (OB_NOT_NULL(fk_state_node->children_[2])) {
arg.enable_flag_ = (T_ENABLE_CONSTRAINT == fk_state_node->children_[2]->type_ ? true : false);
arg.validate_flag_ = (T_ENABLE_CONSTRAINT == fk_state_node->children_[2]->type_ ? true : false);
}
if (OB_NOT_NULL(fk_state_node->children_[3])) {
arg.validate_flag_ = (T_VALIDATE_CONSTRAINT == fk_state_node->children_[3]->type_ ? true : false);
}
}
return ret;
}
int ObDDLResolver::check_foreign_key_reference(
obrpc::ObCreateForeignKeyArg& arg, bool is_alter_table, const ObColumnSchemaV2* column)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(session_info_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "session_info_ is null.", K(ret));
} else {
ObCreateTableStmt* create_table_stmt = NULL;
const ObTableSchema* child_table_schema = NULL;
const ObTableSchema* parent_table_schema = NULL;
ObString& database_name = arg.parent_database_;
ObString& parent_table_name = arg.parent_table_;
if (!is_alter_table) {
create_table_stmt = static_cast<ObCreateTableStmt*>(stmt_);
if (OB_ISNULL(create_table_stmt)) {
ret = OB_NOT_INIT;
SQL_RESV_LOG(WARN, "stmt_ is null.", K(ret));
} else {
child_table_schema = &create_table_stmt->get_create_table_arg().schema_;
}
} else { // is alter table
ObAlterTableStmt* alter_table_stmt = static_cast<ObAlterTableStmt*>(stmt_);
if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(),
alter_table_stmt->get_org_database_name(),
alter_table_stmt->get_org_table_name(),
false,
child_table_schema))) {
LOG_WARN("table is not exist", K(database_name), K(parent_table_name), K(ret));
} else if (OB_ISNULL(child_table_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("parent table schema is null", K(ret));
}
}
if (OB_SUCC(ret)) {
if (0 == parent_table_name.case_compare(table_name_) && 0 == database_name.case_compare(database_name_)) {
parent_table_schema = child_table_schema;
ObSEArray<ObString, 8>& parent_columns = arg.parent_columns_;
ObSEArray<ObString, 8>& child_columns = arg.child_columns_;
bool is_conflicted = false;
for (int64_t i = 0; OB_SUCC(ret) && !is_conflicted && i < parent_columns.count(); ++i) {
for (int64_t j = 0; OB_SUCC(ret) && !is_conflicted && j < child_columns.count(); ++j) {
if (0 == parent_columns.at(i).compare(child_columns.at(j))) {
is_conflicted = true;
ret = OB_ERR_CANNOT_ADD_FOREIGN;
LOG_WARN("cannot support that parent column is in child column list", K(ret));
}
}
}
} else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(),
database_name,
parent_table_name,
false,
parent_table_schema))) {
LOG_WARN("table is not exist", K(database_name), K(parent_table_name), K(ret));
} else if (OB_ISNULL(parent_table_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("parent table schema is null", K(ret));
}
}
if (OB_SUCC(ret)) {
if (!child_table_schema->is_user_table() || !parent_table_schema->is_user_table()) {
ret = OB_ERR_CANNOT_ADD_FOREIGN;
LOG_WARN("foreign key cannot be based on non-user table",
K(ret),
K(child_table_schema->is_user_table()),
K(parent_table_schema->is_user_table()));
} else {
ObSEArray<ObString, 8>& child_columns = arg.child_columns_;
ObSEArray<ObString, 8>& parent_columns = arg.parent_columns_;
if (OB_FAIL(ObResolverUtils::check_foreign_key_columns_type(
*child_table_schema, *parent_table_schema, child_columns, parent_columns, column))) {
LOG_WARN("Failed to check_foreign_key_columns_type", K(ret));
} else {
bool is_matched = false;
ObSArray<ObCreateIndexArg> index_arg_list;
if (!is_alter_table) {
if (parent_table_schema->get_table_id() == child_table_schema->get_table_id()) {
index_arg_list.assign(create_table_stmt->get_index_arg_list());
}
}
if (OB_FAIL(ObResolverUtils::foreign_key_column_match_uk_pk_column(
*parent_table_schema, *schema_checker_, parent_columns, index_arg_list, arg, is_matched))) {
LOG_WARN("Failed to check reference columns in parent table");
} else if (!is_matched) {
if (share::is_mysql_mode()) {
ret = OB_ERR_CANNOT_ADD_FOREIGN;
LOG_WARN("reference columns aren't reference to pk or uk in parent table", K(ret));
} else { // oracle mode
ret = OB_ERR_NO_MATCHING_UK_PK_FOR_COL_LIST;
LOG_WARN("reference columns aren't reference to pk or uk in parent table", K(ret));
}
} else {
} // do-nothing
}
}
}
}
return ret;
}
int ObDDLResolver::resolve_match_options(const ParseNode* match_options_node)
{
int ret = OB_SUCCESS;
if (OB_NOT_NULL(match_options_node)) {
LOG_WARN("the function of match options on foreign key is not supported now.");
if (T_FOREIGN_KEY_MATCH != match_options_node->type_) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid argument", K(ret), K(match_options_node->type_));
} else {
switch (match_options_node->int32_values_[0]) {
case T_SIMPLE:
break;
case T_FULL:
break;
case T_PARTIAL:
break;
default:
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid reference option", K(ret), K(match_options_node->int32_values_[0]));
break;
}
}
} else {
}
return ret;
}
int ObDDLResolver::create_fk_cons_name_automatically(ObString& foreign_key_name)
{
int ret = OB_SUCCESS;
char temp_str_buf[number::ObNumber::MAX_PRINTABLE_SIZE];
ObString cons_name_str;
bool is_exist = false;
ObString tmp_table_name;
if (table_name_.length() > OB_ORACLE_CONS_OR_IDX_CUTTED_NAME_LEN) {
if (OB_FAIL(ob_sub_str(*allocator_, table_name_, 0, OB_ORACLE_CONS_OR_IDX_CUTTED_NAME_LEN - 1, tmp_table_name))) {
SQL_RESV_LOG(WARN, "failed to cut table to 60 byte", K(ret), K(table_name_));
}
} else {
tmp_table_name = table_name_;
}
if (OB_SUCC(ret)) {
// use timestamp to ensure fk name unique
if (snprintf(temp_str_buf,
sizeof(temp_str_buf),
"%.*s_OBFK_%ld",
tmp_table_name.length(),
tmp_table_name.ptr(),
ObTimeUtility::current_time()) < 0) {
ret = OB_SIZE_OVERFLOW;
SQL_RESV_LOG(WARN, "failed to generate buffer for temp_str_buf", K(ret));
} else if (OB_FAIL(ob_write_string(*allocator_, ObString::make_string(temp_str_buf), cons_name_str))) {
SQL_RESV_LOG(WARN, "Can not malloc space for constraint name", K(ret));
} else {
int hash_ret = OB_HASH_NOT_EXIST;
ObForeignKeyNameHashWrapper fk_key(foreign_key_name);
foreign_key_name.assign_ptr(cons_name_str.ptr(), cons_name_str.length());
// re-generate if fk name duplicated
if (OB_HASH_EXIST == (hash_ret = current_foreign_key_name_set_.exist_refactored(fk_key))) {
is_exist = true;
}
if (true == is_exist) {
if (OB_FAIL(create_fk_cons_name_automatically(foreign_key_name))) {
SQL_RESV_LOG(WARN, "create cons name automatically failed", K(ret));
}
} else {
if (OB_FAIL(current_foreign_key_name_set_.set_refactored(fk_key))) {
SQL_RESV_LOG(WARN, "set foreign key name to hash set failed", K(ret), K(foreign_key_name));
}
}
}
}
return ret;
}
int ObDDLResolver::create_name_for_empty_partition(
const bool is_subpartition, ObIArray<ObPartition>& partitions, ObIArray<ObSubPartition>& subpartitions)
{
int ret = OB_SUCCESS;
if (is_subpartition) {
if (OB_FAIL(create_name_for_empty_partition(subpartitions))) {
LOG_WARN("failed to create name for empty subpartitions", K(ret));
}
} else if (OB_FAIL(create_name_for_empty_partition(partitions))) {
LOG_WARN("failed to create name for empty partitions", K(ret));
}
return ret;
}
int ObDDLResolver::store_part_key(const ObTableSchema& table_schema, obrpc::ObCreateIndexArg& index_arg)
{
int ret = OB_SUCCESS;
ObSEArray<uint64_t, 4> part_key_ids;
ObSEArray<uint64_t, 4> index_rowkey_ids;
const ObColumnSchemaV2* column = NULL;
const bool check_column_exists = false;
const bool is_hidden = true;
if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_2250) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("Create global index on no pk partitioned table not supported in old version", K(ret));
} else if (OB_UNLIKELY(!table_schema.is_partitioned_table())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected partition level", K(ret), K(table_schema.get_part_level()));
} else if (OB_FAIL(table_schema.get_partition_key_info().get_column_ids(part_key_ids))) {
LOG_WARN("failed to get column ids", K(ret));
} else if (PARTITION_LEVEL_TWO == table_schema.get_part_level() &&
OB_FAIL(table_schema.get_subpartition_key_info().get_column_ids(part_key_ids))) {
LOG_WARN("failed to get column ids", K(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && i < index_arg.index_columns_.count(); ++i) {
const ObColumnSortItem& column_item = index_arg.index_columns_.at(i);
if (OB_FAIL(index_rowkey_ids.push_back(column_item.column_id_))) {
LOG_WARN("failed to push back column id", K(ret));
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < part_key_ids.count(); ++i) {
uint64_t column_id = part_key_ids.at(i);
if (ObOptimizerUtil::find_item(index_rowkey_ids, column_id)) {
// part key already in index rowkey, do nothing
} else if (OB_ISNULL(column = table_schema.get_column_schema(column_id))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (OB_FAIL(add_storing_column(column->get_column_name_str(), check_column_exists, is_hidden))) {
LOG_WARN("failed to add storing column", K(ret));
}
}
LOG_TRACE("store part key", K(hidden_store_column_names_));
return ret;
}
bool ObDDLResolver::is_column_exists(
ObIArray<ObColumnNameWrapper>& sort_column_array, ObColumnNameWrapper& column_key, bool check_prefix_len)
{
int bret = false;
for (int64_t i = 0; !bret && i < sort_column_array.count(); ++i) {
if (check_prefix_len) {
if (sort_column_array.at(i).all_equal(column_key)) {
bret = true;
}
} else if (sort_column_array.at(i).name_equal(column_key)) {
bret = true;
}
}
return bret;
}
int ObDDLResolver::get_enable_split_partition(const int64_t tenant_id, bool& enable_split_partition)
{
int ret = OB_SUCCESS;
enable_split_partition = false;
if (OB_INVALID_TENANT_ID == tenant_id) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("tenant id is invalid", K(ret), K(tenant_id));
}
return ret;
}
int ObDDLResolver::resolve_partition_name(
ParseNode* partition_name_node, ObString& partition_name, ObBasePartition& partition)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(partition_name_node) || OB_ISNULL(partition_name_node->children_[NAMENODE])) {
if (is_oracle_mode()) {
partition.set_is_empty_partition_name(true);
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition expr list node is null", K(ret));
}
} else {
ParseNode* name_node = partition_name_node->children_[NAMENODE];
partition_name.assign_ptr(name_node->str_value_, static_cast<int32_t>(name_node->str_len_));
if (partition_name.length() > OB_MAX_PARTITION_NAME_LENGTH) {
ret = OB_ERR_TOO_LONG_IDENT;
} else if (OB_FAIL(partition.set_part_name(partition_name))) {
LOG_WARN("failed to set part name", K(ret));
}
}
return ret;
}
int ObDDLResolver::resolve_partition_part_id(ParseNode* part_id_node, const ObDDLStmt* stmt,
const int64_t max_used_part_id, const int64_t partition_num, const int64_t partition_element_idx, int64_t& part_id,
bool& is_spec_part_id)
{
int ret = OB_SUCCESS;
is_spec_part_id = false;
if (OB_ISNULL(part_id_node)) {
part_id =
max_used_part_id >= 0 ? max_used_part_id - partition_num + 1 + partition_element_idx : partition_element_idx;
} else {
part_id = static_cast<int32_t>(part_id_node->children_[0]->value_);
is_spec_part_id = true;
bool is_valid = false;
if (OB_FAIL(check_partid_valid(stmt, part_id, max_used_part_id, is_valid))) {
LOG_WARN("failed to check partid valid", K(ret));
} else if (!is_valid) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("part id not valid", K(ret), K(part_id));
}
}
if (OB_SUCC(ret) && part_id < 0) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid part_id", K(ret), K(part_id));
}
return ret;
}
// resolve hash/key partition basic infos, include:
// 1. partition function type
// 2. partition function expr name
// 3. partition keys (set in this function)
int ObDDLResolver::resolve_hash_or_key_partition_basic_infos(ParseNode* node, bool is_subpartition,
ObTableSchema& table_schema, ObPartitionFuncType& part_func_type, ObString& func_expr_name, ObSqlString& part_str)
{
int ret = OB_SUCCESS;
ParseNode* partition_fun_node = NULL;
part_func_type = PARTITION_FUNC_TYPE_HASH;
const share::schema::ObTablegroupSchema* tablegroup_schema = NULL;
if (OB_ISNULL(node) || OB_ISNULL(node->children_) ||
OB_ISNULL(partition_fun_node = node->children_[HASH_FUN_EXPR_NODE]) || OB_ISNULL(schema_checker_) ||
OB_ISNULL(session_info_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(node), K(partition_fun_node), K(schema_checker_), K(session_info_));
} else if (GET_MIN_CLUSTER_VERSION() >= CLUSTER_VERSION_3000 && !table_schema.get_tablegroup_name().empty() &&
OB_FAIL(schema_checker_->get_tablegroup_schema(
session_info_->get_effective_tenant_id(), table_schema.get_tablegroup_name(), tablegroup_schema))) {
LOG_WARN("fail to get tablegroup schema", K(ret), K(table_schema.get_tablegroup_name()));
} else {
if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_3000) {
part_func_type = T_HASH_PARTITION == node->type_ ? share::schema::PARTITION_FUNC_TYPE_HASH
: share::schema::PARTITION_FUNC_TYPE_KEY_V2;
} else {
part_func_type = T_HASH_PARTITION == node->type_ ? share::schema::PARTITION_FUNC_TYPE_HASH_V2
: share::schema::PARTITION_FUNC_TYPE_KEY_V3;
}
// compatible with old version
if (tablegroup_schema != NULL) {
if (tablegroup_schema->get_part_level() >= table_schema.get_part_level()) {
const share::schema::ObPartitionOption& tablegroup_part =
!is_subpartition ? tablegroup_schema->get_part_option() : tablegroup_schema->get_sub_part_option();
if (part_func_type == share::schema::PARTITION_FUNC_TYPE_HASH_V2 &&
tablegroup_part.get_part_func_type() == share::schema::PARTITION_FUNC_TYPE_HASH) {
part_func_type = share::schema::PARTITION_FUNC_TYPE_HASH;
} else if (part_func_type == share::schema::PARTITION_FUNC_TYPE_KEY_V3 &&
tablegroup_part.get_part_func_type() == share::schema::PARTITION_FUNC_TYPE_KEY_V2) {
part_func_type = share::schema::PARTITION_FUNC_TYPE_KEY_V2;
} else { /*do nothing */
}
}
}
}
if (OB_SUCC(ret)) {
if (NULL == partition_fun_node->children_[1]) { // partition by key()
if (GET_MIN_CLUSTER_VERSION() < CLUSTER_VERSION_3000) {
part_func_type = share::schema::PARTITION_FUNC_TYPE_KEY_IMPLICIT;
} else {
part_func_type = share::schema::PARTITION_FUNC_TYPE_KEY_IMPLICIT_V2;
}
if (OB_FAIL(build_partition_key_info(
table_schema, is_subpartition, part_func_type == share::schema::PARTITION_FUNC_TYPE_KEY_IMPLICIT_V2))) {
LOG_WARN("failed to build partition key info", K(ret), K(table_schema), K(is_subpartition));
}
} else {
ObSEArray<ObRawExpr*, 4> dummy_part_func_exprs;
ObSEArray<ObString, 4> partition_keys;
if (OB_FAIL(resolve_part_func(
params_, partition_fun_node, part_func_type, table_schema, dummy_part_func_exprs, partition_keys))) {
LOG_WARN("failed to resolve part func", K(ret));
} else if (OB_FAIL(set_partition_keys(table_schema, partition_keys, is_subpartition))) {
LOG_WARN("failed to set partition keys", K(ret), K(table_schema), K(is_subpartition));
}
}
}
if (OB_SUCC(ret)) {
func_expr_name.assign_ptr(node->str_value_, static_cast<int32_t>(node->str_len_));
if (!share::is_oracle_mode()) {
// TODO(:maybe not valid here, if expr include table name or databae name)
ObCharset::casedn(CS_TYPE_UTF8MB4_GENERAL_CI, func_expr_name);
}
// TODO now, just for compat inner_table process.
if (is_inner_table(table_id_)) {
if (OB_FAIL(get_part_str_with_type(part_func_type, func_expr_name, part_str))) {
SQL_RESV_LOG(WARN, "Failed to get part str with type", K(ret));
} else if (FALSE_IT(func_expr_name = part_str.string())) {
} else if (PARTITION_FUNC_TYPE_KEY_V2 == part_func_type || PARTITION_FUNC_TYPE_KEY_V3 == part_func_type) {
part_func_type = PARTITION_FUNC_TYPE_KEY;
}
}
}
return ret;
}
// resolve range partition basic infos, include:
// 1. partition function type
// 2. partition function expr name
// 3. partition function exprs
// 4. partition keys (set in this function)
int ObDDLResolver::resolve_range_partition_basic_infos(ParseNode* node, bool is_subpartition,
ObTableSchema& table_schema, ObPartitionFuncType& part_func_type, ObString& func_expr_name,
ObIArray<ObRawExpr*>& part_func_exprs)
{
int ret = OB_SUCCESS;
ParseNode* partition_fun_node = NULL;
part_func_type = PARTITION_FUNC_TYPE_RANGE;
ObSEArray<ObString, 4> partition_keys;
if (OB_ISNULL(node) || OB_ISNULL(partition_fun_node = node->children_[RANGE_FUN_EXPR_NODE])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(node), K(partition_fun_node));
} else if (T_RANGE_COLUMNS_PARTITION == node->type_) {
part_func_type = PARTITION_FUNC_TYPE_RANGE_COLUMNS;
}
if (OB_SUCC(ret)) {
func_expr_name.assign_ptr(node->str_value_, static_cast<int32_t>(node->str_len_));
if (OB_FAIL(resolve_part_func(
params_, partition_fun_node, part_func_type, table_schema, part_func_exprs, partition_keys))) {
LOG_WARN("resolve part func failed", K(ret));
} else if (OB_FAIL(set_partition_keys(table_schema, partition_keys, is_subpartition))) {
LOG_WARN("Failed to set partition keys", K(ret), K(table_schema), K(is_subpartition));
}
}
return ret;
}
// resolve list partition basic infos, include:
// 1. partition function type
// 2. partition function expr name
// 3. partition function exprs
// 4. partition keys (set in this function)
int ObDDLResolver::resolve_list_partition_basic_infos(ParseNode* node, bool is_subpartition,
ObTableSchema& table_schema, ObPartitionFuncType& part_func_type, ObString& func_expr_name,
ObIArray<ObRawExpr*>& part_func_exprs)
{
int ret = OB_SUCCESS;
ParseNode* partition_fun_node = NULL;
part_func_type = PARTITION_FUNC_TYPE_LIST;
ObSEArray<ObString, 4> partition_keys;
if (OB_ISNULL(node) || OB_ISNULL(partition_fun_node = node->children_[LIST_FUN_EXPR_NODE])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(node), K(partition_fun_node));
} else if (T_LIST_COLUMNS_PARTITION == node->type_) {
part_func_type = PARTITION_FUNC_TYPE_LIST_COLUMNS;
}
if (OB_SUCC(ret)) {
func_expr_name.assign_ptr(node->str_value_, static_cast<int32_t>(node->str_len_));
if (OB_FAIL(resolve_part_func(
params_, partition_fun_node, part_func_type, table_schema, part_func_exprs, partition_keys))) {
LOG_WARN("resolve part func failed", K(ret));
} else if (OB_FAIL(set_partition_keys(table_schema, partition_keys, is_subpartition))) {
LOG_WARN("Failed to set partition keys", K(ret), K(table_schema), K(is_subpartition));
}
}
return ret;
}
int ObDDLResolver::resolve_partition_node(ObPartitionedStmt* stmt, ParseNode* part_node, ObTableSchema& table_schema)
{
int ret = OB_SUCCESS;
if (is_hash_type_partition(part_node->type_)) {
ret = resolve_partition_hash_or_key(stmt, part_node, false, table_schema);
} else if (is_range_type_partition(part_node->type_)) {
ret = resolve_partition_range(stmt, part_node, false, table_schema);
} else if (is_list_type_partition(part_node->type_)) {
ret = resolve_partition_list(stmt, part_node, false, table_schema);
} else {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "node type is invalid.", K(ret), K(part_node->type_));
}
if (OB_SUCC(ret) && !common::is_virtual_table(table_id_)) {
if (table_schema.get_all_part_num() >
(lib::is_oracle_mode() ? common::OB_MAX_PARTITION_NUM_ORACLE : common::OB_MAX_PARTITION_NUM_MYSQL)) {
ret = common::OB_TOO_MANY_PARTITIONS_ERROR;
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(check_and_set_partition_names(stmt, table_schema))) {
LOG_WARN("failed to check and set partition names", K(ret));
}
}
return ret;
}
int ObDDLResolver::resolve_subpartition_option(
ObPartitionedStmt* stmt, ParseNode* subpart_node, ObTableSchema& table_schema)
{
int ret = OB_SUCCESS;
if (is_hash_type_partition(subpart_node->type_)) {
if (OB_FAIL(resolve_partition_hash_or_key(stmt, subpart_node, true, table_schema))) {
SQL_RESV_LOG(WARN, "failed to resolve partition hash or key", K(ret));
}
} else if (is_range_type_partition(subpart_node->type_)) {
if (OB_FAIL(resolve_partition_range(stmt, subpart_node, true, table_schema))) {
SQL_RESV_LOG(WARN, "failed to resolve partition range", K(ret));
}
} else if (is_list_type_partition(subpart_node->type_)) {
if (OB_FAIL(resolve_partition_list(stmt, subpart_node, true, table_schema))) {
SQL_RESV_LOG(WARN, "failed to resolve partition list", K(ret));
}
} else {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "get unexpected subpartition type", K(ret), K(subpart_node->type_));
}
return ret;
}
int ObDDLResolver::resolve_individual_subpartition(ObPartitionedStmt* stmt, ParseNode* part_node,
ParseNode* partition_list_node, ParseNode* subpart_node, share::schema::ObTableSchema& table_schema,
bool& force_template)
{
int ret = OB_SUCCESS;
share::schema::ObPartitionFuncType partition_func_type = share::schema::PARTITION_FUNC_TYPE_HASH;
ObString func_expr_name;
common::ObSEArray<ObRawExpr*, 8> part_func_exprs;
table_schema.set_part_level(share::schema::PARTITION_LEVEL_TWO);
force_template = false;
ObSqlString part_str;
if (OB_ISNULL(stmt) || OB_ISNULL(part_node) || OB_ISNULL(subpart_node)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "get unexpected null", K(ret), K(stmt), K(part_node), K(subpart_node));
} else if (is_range_type_partition(subpart_node->type_)) {
// range subpartition
if (OB_FAIL(resolve_range_partition_basic_infos(
subpart_node, true, table_schema, partition_func_type, func_expr_name, part_func_exprs))) {
SQL_RESV_LOG(WARN, "failed to resolve range partition basic infos", K(ret));
} else if (OB_FAIL(stmt->get_subpart_fun_exprs().assign(part_func_exprs))) {
SQL_RESV_LOG(WARN, "failed to assign range fun exprs", K(ret));
}
} else if (is_list_type_partition(subpart_node->type_)) {
// list subpartition
if (OB_FAIL(resolve_list_partition_basic_infos(
subpart_node, true, table_schema, partition_func_type, func_expr_name, part_func_exprs))) {
SQL_RESV_LOG(WARN, "failed to resolve list partition basic infos", K(ret));
} else if (OB_FAIL(stmt->get_subpart_fun_exprs().assign(part_func_exprs))) {
SQL_RESV_LOG(WARN, "failed to assign range fun exprs", K(ret));
}
} else if (is_hash_type_partition(subpart_node->type_)) {
/**
* create table t1 (c1 int, c2 int) partition by range (c1)
* subpartition by hash (c2) subpartitions 3
* (
* partition p0 values less than (100),
* partition p1 values less than (200)
* );
* create table t2 (c1 int, c2 int) partition by range (c1)
* subpartition by hash (c2) subpartitions 3
* (
* partition p0 values less than (100)
* (
* subpartition p0_h1,
* subpartition p0_h2
* ),
* partition p1 values less than (200)
* );
*/
if (NULL != partition_list_node) {
bool has_def_subpart = false;
for (int64_t i = 0; OB_SUCC(ret) && !has_def_subpart && i < partition_list_node->num_child_; ++i) {
if (OB_ISNULL(partition_list_node->children_[i])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (NULL != partition_list_node->children_[i]->children_[ELEMENT_SUBPARTITION_NODE]) {
has_def_subpart = true;
}
}
if (OB_SUCC(ret) && !has_def_subpart) {
force_template = true;
}
} else {
// auto set templated secondary partitions
force_template = true;
}
if (OB_SUCC(ret) && !force_template) {
if (OB_FAIL(resolve_hash_or_key_partition_basic_infos(
subpart_node, true, table_schema, partition_func_type, func_expr_name, part_str))) {
SQL_RESV_LOG(WARN, "failed to resolve hash or key parititon basic infos", K(ret));
} else if (NULL != subpart_node->children_[HASH_PARTITION_NUM_NODE]) {
hash_subpart_num_ = subpart_node->children_[HASH_PARTITION_NUM_NODE]->value_;
if (hash_subpart_num_ <= 0) {
ret = common::OB_NO_PARTS_ERROR;
LOG_USER_ERROR(OB_NO_PARTS_ERROR);
}
} else {
hash_subpart_num_ = 1;
}
}
}
if (OB_SUCC(ret) && !force_template) {
table_schema.get_sub_part_option().set_part_func_type(partition_func_type);
if (OB_FAIL(table_schema.get_sub_part_option().set_part_expr(func_expr_name))) {
SQL_RESV_LOG(WARN, "set partition express string failed", K(ret));
}
}
return ret;
}
int ObDDLResolver::resolve_subpartition_elements(
ObPartitionedStmt* stmt, ParseNode* node, ObTableSchema& table_schema, ObPartition* partition, bool in_tablegroup)
{
int ret = OB_SUCCESS;
ObPartitionFuncType subpart_type = table_schema.get_sub_part_option().get_part_func_type();
int64_t max_used_subpart_id = -1;
if (OB_ISNULL(partition)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (FALSE_IT(max_used_subpart_id = partition->get_max_used_sub_part_id())) {
} else if (OB_ISNULL(node)) {
if (!is_hash_like_part(subpart_type)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (hash_subpart_num_ < 1) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("default subpart num not specified", K(ret), K(hash_subpart_num_));
} else if (OB_FAIL(
generate_default_hash_subpart(hash_subpart_num_, max_used_subpart_id, table_schema, partition))) {
LOG_WARN("failed to generate default hash subpart", K(ret));
}
} else if ((is_hash_like_part(subpart_type) && node->type_ != T_HASH_SUBPARTITION_LIST) ||
(is_range_part(subpart_type) && node->type_ != T_RANGE_SUBPARTITION_LIST) ||
(is_list_part(subpart_type) && node->type_ != T_LIST_SUBPARTITION_LIST)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("subpartition define is not match declare", K(ret), K(subpart_type), K(node->type_));
} else if (T_HASH_SUBPARTITION_LIST == node->type_) {
if (OB_FAIL(resolve_hash_subpartition_elements(stmt, node, table_schema, partition, max_used_subpart_id))) {
LOG_WARN("failed to resolve hash subpartition elements", K(ret));
}
} else if (T_RANGE_SUBPARTITION_LIST == node->type_) {
ObDDLStmt::array_t range_value_exprs;
if (OB_FAIL(resolve_range_subpartition_elements(stmt,
node,
table_schema,
partition,
subpart_type,
stmt->get_subpart_fun_exprs(),
range_value_exprs,
max_used_subpart_id,
in_tablegroup))) {
LOG_WARN("failed to resolve hash subpartition elements", K(ret));
} else if (OB_FAIL(stmt->get_individual_subpart_values_exprs().push_back(range_value_exprs))) {
LOG_WARN("failed to push back range value exprs");
}
} else if (T_LIST_SUBPARTITION_LIST == node->type_) {
ObDDLStmt::array_t list_value_exprs;
if (OB_FAIL(resolve_list_subpartition_elements(stmt,
node,
table_schema,
partition,
subpart_type,
stmt->get_subpart_fun_exprs(),
list_value_exprs,
max_used_subpart_id,
in_tablegroup))) {
LOG_WARN("failed to resolve hash subpartition elements", K(ret));
} else if (OB_FAIL(stmt->get_individual_subpart_values_exprs().push_back(list_value_exprs))) {
LOG_WARN("failed to push back range value exprs");
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(check_max_used_subpart_id_valid(table_schema, *partition, max_used_subpart_id))) {
LOG_WARN("faield to check max used subpart id", K(ret));
} else {
partition->set_max_used_sub_part_id(max_used_subpart_id);
}
}
return ret;
}
int ObDDLResolver::resolve_partition_hash_or_key(
ObPartitionedStmt* stmt, ParseNode* node, const bool is_subpartition, ObTableSchema& table_schema)
{
int ret = common::OB_SUCCESS;
ObString partition_expr;
ObPartitionFuncType partition_func_type = PARTITION_FUNC_TYPE_HASH;
int64_t partition_num = 0;
ObPartitionOption* partition_option = NULL;
if (OB_ISNULL(node) || OB_ISNULL(node->children_) || !is_hash_type_partition(node->type_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected node", K(ret), K(node));
} else if (is_subpartition && NULL != node->children_[HASH_SUBPARTITIOPPN_NODE]) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("subpartition cannot has another subpartition", K(ret));
} else if (is_subpartition) {
partition_option = &(table_schema.get_sub_part_option());
table_schema.set_part_level(share::schema::PARTITION_LEVEL_TWO);
} else {
partition_option = &(table_schema.get_part_option());
table_schema.set_part_level(share::schema::PARTITION_LEVEL_ONE);
}
if (OB_SUCC(ret)) {
if (NULL != node->children_[HASH_SUBPARTITIOPPN_NODE]) {
bool force_template = false;
if (NULL != node->children_[HASH_SUBPARTITIOPPN_NODE]->children_[HASH_TEMPLATE_MARK]) {
table_schema.set_is_sub_part_template(true);
} else if (OB_FAIL(resolve_individual_subpartition(stmt,
node,
node->children_[HASH_PARTITION_LIST_NODE],
node->children_[HASH_SUBPARTITIOPPN_NODE],
table_schema,
force_template))) {
SQL_RESV_LOG(WARN, "failed to resolve individual subpartition", K(ret));
} else if (force_template) {
table_schema.set_is_sub_part_template(true);
} else {
table_schema.set_is_sub_part_template(false);
}
}
}
// 1. resolve partition type, partition keys, partition expr
if (OB_SUCC(ret)) {
ObSqlString part_str;
if (OB_FAIL(resolve_hash_or_key_partition_basic_infos(
node, is_subpartition, table_schema, partition_func_type, partition_expr, part_str))) {
SQL_RESV_LOG(WARN, "failed to resolve hash or key parititon basic infos", K(ret));
} else {
partition_option->set_part_func_type(partition_func_type);
if (OB_FAIL(partition_option->set_part_expr(partition_expr))) {
SQL_RESV_LOG(WARN, "set partition express string failed", K(ret));
}
}
}
// 2. process part defination
if (OB_SUCC(ret)) {
if (NULL != node->children_[HASH_PARTITION_NUM_NODE]) {
partition_num = node->children_[HASH_PARTITION_NUM_NODE]->value_;
} else if (NULL == node->children_[HASH_PARTITION_LIST_NODE]) {
partition_num = 1;
} else {
partition_num = 1;
}
if (NULL != node->children_[HASH_PARTITION_NUM_NODE] && NULL != node->children_[HASH_PARTITION_LIST_NODE]) {
if (is_oracle_mode()) {
ret = OB_ERR_SPECIFIY_PARTITION_DESCRIPTION;
} else if (partition_num != node->children_[HASH_PARTITION_LIST_NODE]->num_child_) {
ret = OB_ERR_PARSE_PARTITION_RANGE;
}
}
if (OB_FAIL(ret)) {
} else if (partition_num <= 0) {
ret = common::OB_NO_PARTS_ERROR;
LOG_USER_ERROR(OB_NO_PARTS_ERROR);
} else if (!common::is_virtual_table(table_id_) &&
partition_num >
(lib::is_oracle_mode() ? common::OB_MAX_PARTITION_NUM_ORACLE : common::OB_MAX_PARTITION_NUM_MYSQL)) {
ret = common::OB_TOO_MANY_PARTITIONS_ERROR;
} else if (is_subpartition) {
if (NULL != node->children_[HASH_PARTITION_LIST_NODE]) {
if (OB_FAIL(resolve_hash_subpartition_elements(
stmt, node->children_[HASH_PARTITION_LIST_NODE], table_schema, NULL /* dummy partition*/))) {
SQL_RESV_LOG(WARN, "failed to resolve hash subpartition elements", K(ret));
}
} else {
if (OB_FAIL(generate_default_hash_subpart(partition_num,
-1, // max_used_supart_id
table_schema,
NULL))) { // dummy partition
LOG_WARN("failed to generate default hash part", K(ret));
}
}
} else {
if (NULL != node->children_[HASH_PARTITION_LIST_NODE]) {
if (OB_FAIL(resolve_hash_partition_elements(
stmt, node->children_[HASH_PARTITION_LIST_NODE], table_schema, max_used_part_id_))) {
LOG_WARN("failed to resolve hash partition elements", K(ret));
}
} else {
if (OB_FAIL(generate_default_hash_part(partition_num, max_used_part_id_, table_schema))) {
LOG_WARN("failed to generate default hash part", K(ret));
}
if (!table_schema.is_sub_part_template()) {
if (table_schema.is_hash_like_subpart()) {
// partition by hash(c1) subpartition by hash(c2) subpartitions 3 partitions 3
for (int64_t i = 0; OB_SUCC(ret) && i < table_schema.get_first_part_num(); ++i) {
if (OB_FAIL(resolve_subpartition_elements(stmt,
NULL, // dummy node
table_schema,
table_schema.get_part_array()[i],
false))) {
LOG_WARN("failed to resolve subpartition elements", K(ret));
}
}
} else {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid partition define", K(ret));
}
}
}
}
}
if (OB_SUCC(ret)) {
if (NULL != node->children_[HASH_SUBPARTITIOPPN_NODE] && table_schema.is_sub_part_template()) {
if (OB_FAIL(resolve_subpartition_option(stmt, node->children_[HASH_SUBPARTITIOPPN_NODE], table_schema))) {
SQL_RESV_LOG(WARN, "failed to resolve subpartition", K(ret));
}
}
}
return ret;
}
int ObDDLResolver::resolve_partition_range(
ObPartitionedStmt* stmt, ParseNode* node, const bool is_subpartition, ObTableSchema& table_schema)
{
int ret = OB_SUCCESS;
ObString func_expr_name;
int64_t partition_num = 0;
share::schema::ObPartitionFuncType part_func_type = share::schema::PARTITION_FUNC_TYPE_RANGE;
common::ObSEArray<ObRawExpr*, 8> part_func_exprs;
common::ObSEArray<ObRawExpr*, 8> range_values_exprs;
share::schema::ObPartitionOption* partition_option = NULL;
if (OB_ISNULL(stmt) || OB_ISNULL(node) || OB_ISNULL(node->children_) ||
OB_ISNULL(node->children_[RANGE_ELEMENTS_NODE])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "get unexpected null", K(ret), K(stmt), K(node));
} else if (!is_range_type_partition(node->type_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "get unexpected partition type", K(ret), K(node->type_));
} else if (is_subpartition) {
partition_option = &(table_schema.get_sub_part_option());
table_schema.set_part_level(share::schema::PARTITION_LEVEL_TWO);
} else {
partition_option = &(table_schema.get_part_option());
table_schema.set_part_level(share::schema::PARTITION_LEVEL_ONE);
}
if (OB_SUCC(ret)) {
if (NULL != node->children_[RANGE_SUBPARTITIOPPN_NODE]) {
bool force_template = false;
if (NULL != node->children_[RANGE_SUBPARTITIOPPN_NODE]->children_[RANGE_TEMPLATE_MARK]) {
table_schema.set_is_sub_part_template(true);
} else if (OB_FAIL(resolve_individual_subpartition(stmt,
node,
node->children_[RANGE_ELEMENTS_NODE],
node->children_[RANGE_SUBPARTITIOPPN_NODE],
table_schema,
force_template))) {
SQL_RESV_LOG(WARN, "failed to resolve individual subpartition", K(ret));
} else if (force_template) {
table_schema.set_is_sub_part_template(true);
} else {
table_schema.set_is_sub_part_template(false);
}
}
}
// 1. resolve partition type, partition keys, partition expr
if (OB_SUCC(ret)) {
if (OB_FAIL(resolve_range_partition_basic_infos(
node, is_subpartition, table_schema, part_func_type, func_expr_name, part_func_exprs))) {
SQL_RESV_LOG(WARN, "failed to resolve range partition basic infos", K(ret));
} else if (OB_FAIL(partition_option->set_part_expr(func_expr_name))) {
SQL_RESV_LOG(WARN, "set partition express string failed", K(ret));
} else {
partition_option->set_part_func_type(part_func_type);
}
}
// 2. resolve range partition define
if (OB_SUCC(ret)) {
if (NULL != node->children_[RANGE_PARTITION_NUM_NODE]) {
partition_num = node->children_[RANGE_PARTITION_NUM_NODE]->value_;
if (partition_num != node->children_[RANGE_ELEMENTS_NODE]->num_child_) {
ret = OB_ERR_PARSE_PARTITION_RANGE;
}
} else {
partition_num = node->children_[RANGE_ELEMENTS_NODE]->num_child_;
}
partition_option->set_part_num(partition_num);
if (OB_SUCC(ret)) {
if (OB_FAIL(check_partition_name_duplicate(node->children_[RANGE_ELEMENTS_NODE], lib::is_oracle_mode()))) {
SQL_RESV_LOG(WARN, "duplicate partition name", K(ret));
} else if (is_subpartition) {
if (OB_FAIL(resolve_range_subpartition_elements(stmt,
node->children_[RANGE_ELEMENTS_NODE],
table_schema,
NULL, // dummy partition
part_func_type,
part_func_exprs,
range_values_exprs,
-1 /* max_used_subpart_id */))) {
SQL_RESV_LOG(WARN, "resolve reange partition elements fail", K(ret));
}
} else {
if (OB_FAIL(resolve_range_partition_elements(stmt,
node->children_[RANGE_ELEMENTS_NODE],
table_schema,
part_func_type,
part_func_exprs,
range_values_exprs,
max_used_part_id_))) {
SQL_RESV_LOG(WARN, "resolve reange partition elements fail", K(ret));
}
}
}
}
if (OB_SUCC(ret)) {
if (NULL != node->children_[RANGE_SUBPARTITIOPPN_NODE] && table_schema.is_sub_part_template()) {
if (OB_FAIL(resolve_subpartition_option(stmt, node->children_[RANGE_SUBPARTITIOPPN_NODE], table_schema))) {
SQL_RESV_LOG(WARN, "failed to resolve subpartition", K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (is_subpartition) {
if (OB_FAIL(stmt->get_subpart_fun_exprs().assign(part_func_exprs))) {
SQL_RESV_LOG(WARN, "failed to assign range fun exprs", K(ret));
} else if (OB_FAIL(stmt->get_template_subpart_values_exprs().assign(range_values_exprs))) {
SQL_RESV_LOG(WARN, "failed to assign range values exprs", K(ret));
}
} else {
if (OB_FAIL(stmt->get_part_fun_exprs().assign(part_func_exprs))) {
SQL_RESV_LOG(WARN, "failed to assign range fun exprs", K(ret));
} else if (OB_FAIL(stmt->get_part_values_exprs().assign(range_values_exprs))) {
SQL_RESV_LOG(WARN, "failed to assign range values exprs", K(ret));
}
}
SQL_RESV_LOG(DEBUG, "succ to resolve_partition_range", KPC(stmt), K(part_func_exprs), K(range_values_exprs));
}
return ret;
}
int ObDDLResolver::resolve_partition_list(
ObPartitionedStmt* stmt, ParseNode* node, const bool is_subpartition, ObTableSchema& table_schema)
{
int ret = OB_SUCCESS;
ObString func_expr_name;
ObPartitionOption* partition_option = NULL;
int64_t partition_num = 0;
ObPartitionFuncType part_func_type = PARTITION_FUNC_TYPE_LIST;
common::ObSEArray<ObRawExpr*, 8> part_func_exprs;
ObDDLStmt::array_t list_values_exprs;
if (OB_ISNULL(stmt) || OB_ISNULL(node) || OB_ISNULL(node->children_) ||
OB_ISNULL(node->children_[LIST_ELEMENTS_NODE])) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "get unexpected null", K(ret), K(stmt), K(node));
} else if (!is_list_type_partition(node->type_)) {
ret = OB_ERR_UNEXPECTED;
SQL_RESV_LOG(WARN, "get unexpected partition type", K(ret), K(node->type_));
} else if (is_subpartition) {
partition_option = &(table_schema.get_sub_part_option());
table_schema.set_part_level(share::schema::PARTITION_LEVEL_TWO);
} else {
partition_option = &(table_schema.get_part_option());
table_schema.set_part_level(share::schema::PARTITION_LEVEL_ONE);
}
if (OB_SUCC(ret)) {
if (NULL != node->children_[LIST_SUBPARTITIOPPN_NODE]) {
bool force_template = false;
if (NULL != node->children_[LIST_SUBPARTITIOPPN_NODE]->children_[LIST_TEMPLATE_MARK]) {
table_schema.set_is_sub_part_template(true);
} else if (OB_FAIL(resolve_individual_subpartition(stmt,
node,
node->children_[LIST_ELEMENTS_NODE],
node->children_[LIST_SUBPARTITIOPPN_NODE],
table_schema,
force_template))) {
SQL_RESV_LOG(WARN, "failed to resolve individual subpartition", K(ret));
} else if (force_template) {
table_schema.set_is_sub_part_template(true);
} else {
table_schema.set_is_sub_part_template(false);
}
}
}
// 1. resolve partition type, partition keys, partition expr
if (OB_SUCC(ret)) {
if (OB_FAIL(resolve_list_partition_basic_infos(
node, is_subpartition, table_schema, part_func_type, func_expr_name, part_func_exprs))) {
SQL_RESV_LOG(WARN, "failed to resolve range partition basic infos", K(ret));
} else if (OB_FAIL(partition_option->set_part_expr(func_expr_name))) {
SQL_RESV_LOG(WARN, "set partition express string failed", K(ret));
} else {
partition_option->set_part_func_type(part_func_type);
}
}
if (OB_SUCC(ret)) {
if (!OB_ISNULL(node->children_[LIST_PARTITION_NUM_NODE])) {
partition_num = node->children_[LIST_PARTITION_NUM_NODE]->value_;
if (partition_num != node->children_[LIST_ELEMENTS_NODE]->num_child_) {
ret = common::OB_ERR_PARSE_PARTITION_LIST;
}
} else {
partition_num = node->children_[LIST_ELEMENTS_NODE]->num_child_;
}
partition_option->set_part_num(partition_num);
if (OB_SUCC(ret)) {
if (OB_FAIL(check_partition_name_duplicate(node->children_[LIST_ELEMENTS_NODE], lib::is_oracle_mode()))) {
SQL_RESV_LOG(WARN, "duplicate partition name", K(ret));
} else if (is_subpartition) {
if (OB_FAIL(resolve_list_subpartition_elements(stmt,
node->children_[LIST_ELEMENTS_NODE],
table_schema,
NULL, // dummy partition
part_func_type,
part_func_exprs,
list_values_exprs,
-1))) {
SQL_RESV_LOG(WARN, "resolve reange partition elements fail", K(ret));
}
} else {
if (OB_FAIL(resolve_list_partition_elements(stmt,
node->children_[LIST_ELEMENTS_NODE],
table_schema,
part_func_type,
part_func_exprs,
list_values_exprs,
max_used_part_id_))) {
SQL_RESV_LOG(WARN, "resolve reange partition elements fail", K(ret));
}
}
}
}
if (OB_SUCC(ret)) {
if (NULL != node->children_[LIST_SUBPARTITIOPPN_NODE] && table_schema.is_sub_part_template()) {
if (OB_FAIL(resolve_subpartition_option(stmt, node->children_[LIST_SUBPARTITIOPPN_NODE], table_schema))) {
SQL_RESV_LOG(WARN, "failed to resolve subpartition", K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (is_subpartition) {
if (OB_FAIL(stmt->get_subpart_fun_exprs().assign(part_func_exprs))) {
SQL_RESV_LOG(WARN, "failed to assign range fun exprs", K(ret));
} else if (OB_FAIL(stmt->get_template_subpart_values_exprs().assign(list_values_exprs))) {
SQL_RESV_LOG(WARN, "failed to assign range values exprs", K(ret));
}
} else {
if (OB_FAIL(stmt->get_part_fun_exprs().assign(part_func_exprs))) {
SQL_RESV_LOG(WARN, "failed to assign range fun exprs", K(ret));
} else if (OB_FAIL(stmt->get_part_values_exprs().assign(list_values_exprs))) {
SQL_RESV_LOG(WARN, "failed to assign range values exprs", K(ret));
}
}
SQL_RESV_LOG(DEBUG, "succ to resolve_partition_list", KPC(stmt), K(part_func_exprs), K(list_values_exprs));
}
return ret;
}
int ObDDLResolver::resolve_hash_partition_elements(
ObPartitionedStmt* stmt, ParseNode* node, ObTableSchema& table_schema, int64_t max_used_part_id)
{
int ret = OB_SUCCESS;
ParseNode* element_node = NULL;
if (OB_ISNULL(node) || OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(node), K(stmt));
} else if (max_used_part_id >= 0 && max_used_part_id < node->num_child_ - 1) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("max_used_part_id is invalid", K(ret), K(max_used_part_id), K(node->num_child_));
} else {
int64_t partition_num = node->num_child_;
ObPartition partition;
bool init_specified = false;
// ignore alter_table with part_id
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
partition.reset();
ObString partition_name;
int64_t part_id = OB_INVALID_ID;
bool current_spec = false;
// 1. check partition name
if (OB_ISNULL(element_node = node->children_[i])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(element_node));
} else if (OB_FAIL(
resolve_partition_name(element_node->children_[PARTITION_NAME_NODE], partition_name, partition))) {
LOG_WARN("failed to resolve partition name", K(ret));
} else if (OB_FAIL(resolve_partition_part_id(element_node->children_[PART_ID_NODE],
stmt,
max_used_part_id,
partition_num,
i,
part_id,
current_spec))) {
LOG_WARN("failed to resolve partition part id", K(ret));
} else {
// all partition should both specified part id or not
if (0 == i) {
init_specified = current_spec;
} else if (current_spec != init_specified) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Should speicify part id for all parts", K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
}
}
// add hash partition elements to table schema
if (OB_SUCC(ret)) {
partition.set_part_id(part_id);
partition.set_part_idx(i);
if (OB_FAIL(table_schema.check_part_id(partition))) {
LOG_WARN("failed to check part id", K(ret));
} else if (OB_FAIL(table_schema.add_partition(partition))) {
LOG_WARN("failed to add partition", K(ret));
} else if (table_schema.is_sub_part_template() &&
OB_NOT_NULL(element_node->children_[ELEMENT_SUBPARTITION_NODE])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("individual subpartition with sub part template", K(ret));
} else if (!table_schema.is_sub_part_template()) {
// resolve non template
ObPartition* cur_partition = table_schema.get_part_array()[i];
if (OB_ISNULL(cur_partition)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (OB_FAIL(resolve_subpartition_elements(stmt,
element_node->children_[ELEMENT_SUBPARTITION_NODE],
table_schema,
cur_partition,
false))) {
LOG_WARN("failed to resolve subpartition elements", K(ret));
}
}
}
}
if (OB_SUCC(ret)) {
table_schema.get_part_option().set_part_num(partition_num);
}
}
return ret;
}
int ObDDLResolver::resolve_hash_subpartition_elements(ObPartitionedStmt* stmt, ParseNode* node,
ObTableSchema& table_schema, ObPartition* partition, int64_t max_used_subpart_id)
{
int ret = OB_SUCCESS;
ParseNode* element_node = NULL;
const bool is_template = table_schema.is_sub_part_template();
if (OB_ISNULL(node) || OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(node), K(stmt));
} else if (!is_template && OB_ISNULL(partition)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition is null while not sub part template", K(ret));
} else if (max_used_subpart_id >= 0 && max_used_subpart_id < node->num_child_ - 1) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("max_used_subpart_id is invalid", K(ret), K(max_used_subpart_id), K(node->num_child_));
} else {
const int64_t part_id = is_template ? ObSubPartition::TEMPLATE_PART_ID : partition->get_part_id();
int64_t partition_num = node->num_child_;
ObSubPartition subpartition;
bool init_specified = false;
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
subpartition.reset();
ObString partition_name;
int64_t subpart_id = OB_INVALID_ID;
bool current_spec = false;
// 1. check partition name
if (OB_ISNULL(element_node = node->children_[i])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (OB_FAIL(resolve_partition_name(
element_node->children_[PARTITION_NAME_NODE], partition_name, subpartition))) {
LOG_WARN("failed to resolve partition name", K(ret));
} else if (OB_FAIL(resolve_partition_part_id(element_node->children_[PART_ID_NODE],
stmt,
max_used_subpart_id,
partition_num,
i,
subpart_id,
current_spec))) {
LOG_WARN("failed to resolve partition part id", K(ret));
} else {
// all partition should both specified part id or not
if (0 == i) {
init_specified = current_spec;
} else if (init_specified != current_spec) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Should speicify part id for all parts", K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
}
}
// add hash subpartition elements to table schema or partition
if (OB_SUCC(ret)) {
subpartition.set_part_id(part_id);
subpartition.set_sub_part_id(subpart_id);
subpartition.set_sub_part_idx(i);
if (is_template) {
if (OB_FAIL(table_schema.add_def_subpartition(subpartition))) {
LOG_WARN("failed to add partition", K(ret));
}
} else if (OB_FAIL(partition->add_partition(subpartition))) {
LOG_WARN("failed to add partition", K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (is_template) {
table_schema.get_sub_part_option().set_part_num(partition_num);
} else {
partition->set_sub_part_num(partition_num);
}
}
}
return ret;
}
int ObDDLResolver::resolve_range_partition_elements(ObPartitionedStmt* stmt, ParseNode* node,
ObTableSchema& table_schema, const ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
ObIArray<ObRawExpr*>& range_value_exprs, int64_t max_used_part_id, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
ParseNode* element_node = NULL;
ParseNode* expr_list_node = NULL;
if (OB_ISNULL(node) || OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null or stmt is null", K(ret), K(node), K(stmt));
} else if (max_used_part_id >= 0 && max_used_part_id < node->num_child_ - 1) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("max_used_part_id is invalid", K(ret), K(max_used_part_id), K(node->num_child_));
} else {
int64_t partition_num = node->num_child_;
ObPartition partition;
bool init_specified = false;
// ignore alter_table with part_id
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
partition.reset();
ObString partition_name;
int64_t part_id = OB_INVALID_ID;
bool current_spec = false;
if (OB_ISNULL(element_node = node->children_[i]) ||
OB_ISNULL(expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE]) ||
OB_UNLIKELY(T_EXPR_LIST != expr_list_node->type_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected node", K(ret), K(element_node), K(expr_list_node));
} else if (part_func_exprs.count() != expr_list_node->num_child_) {
ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
} else if (OB_FAIL(
resolve_partition_name(element_node->children_[PARTITION_NAME_NODE], partition_name, partition))) {
LOG_WARN("failed to resolve partition name", K(ret));
} else if (OB_FAIL(resolve_range_partition_value_node(
*expr_list_node, partition_name, part_type, part_func_exprs, range_value_exprs, in_tablegroup))) {
LOG_WARN("failed to resolve range partition value node", K(ret));
} else if (OB_FAIL(resolve_partition_part_id(element_node->children_[PART_ID_NODE],
stmt,
max_used_part_id,
partition_num,
i,
part_id,
current_spec))) {
LOG_WARN("failed to resolve partition part id", K(ret));
} else {
if (0 == i) {
init_specified = current_spec;
} else if (current_spec != init_specified) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Should speicify part id for all parts", K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
}
}
// add range partition elements to table schema
if (OB_SUCC(ret)) {
partition.set_part_id(part_id);
if (OB_FAIL(table_schema.check_part_id(partition))) {
LOG_WARN("failed to check part id", K(ret));
} else if (OB_FAIL(table_schema.add_partition(partition))) {
LOG_WARN("failed to add partition", K(ret));
} else if (table_schema.is_sub_part_template() &&
OB_NOT_NULL(element_node->children_[ELEMENT_SUBPARTITION_NODE])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("individual subpartition with sub part template", K(ret));
} else if (!table_schema.is_sub_part_template()) {
// resolve non template
ObPartition* cur_partition = table_schema.get_part_array()[i];
if (OB_ISNULL(cur_partition)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (OB_FAIL(resolve_subpartition_elements(stmt,
element_node->children_[ELEMENT_SUBPARTITION_NODE],
table_schema,
cur_partition,
false))) {
LOG_WARN("failed to resolve subpartition elements", K(ret));
}
}
}
}
if (OB_SUCC(ret)) {
table_schema.get_part_option().set_part_num(partition_num);
}
}
return ret;
}
int ObDDLResolver::resolve_range_subpartition_elements(ObPartitionedStmt* stmt, ParseNode* node,
ObTableSchema& table_schema, ObPartition* partition, const ObPartitionFuncType part_type,
const ObIArray<ObRawExpr*>& part_func_exprs, ObIArray<ObRawExpr*>& range_value_exprs, int64_t max_used_subpart_id,
const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
ParseNode* element_node = NULL;
ParseNode* expr_list_node = NULL;
const bool is_template = table_schema.is_sub_part_template();
if (OB_ISNULL(node) || OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null or stmt is null", K(ret), K(node), K(stmt));
} else if (!is_template && OB_ISNULL(partition)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition is null while not sub part template", K(ret));
} else if (max_used_subpart_id >= 0 && max_used_subpart_id < node->num_child_ - 1) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("max_used_subpart_id is invalid", K(ret), K(max_used_subpart_id), K(node->num_child_));
} else {
int64_t partition_num = node->num_child_;
ObSubPartition subpartition;
bool init_specified = false;
const int64_t part_id = is_template ? ObSubPartition::TEMPLATE_PART_ID : partition->get_part_id();
// ignore alter_table with part_id
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
subpartition.reset();
ObString partition_name;
int64_t subpart_id = OB_INVALID_ID;
bool current_spec = false;
if (OB_ISNULL(element_node = node->children_[i]) ||
OB_ISNULL(expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE]) ||
OB_UNLIKELY(T_EXPR_LIST != expr_list_node->type_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected node", K(ret), K(element_node), K(expr_list_node));
} else if (part_func_exprs.count() != expr_list_node->num_child_) {
ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
} else if (OB_FAIL(resolve_partition_name(
element_node->children_[PARTITION_NAME_NODE], partition_name, subpartition))) {
LOG_WARN("failed to resolve partition name", K(ret));
} else if (OB_FAIL(resolve_range_partition_value_node(
*expr_list_node, partition_name, part_type, part_func_exprs, range_value_exprs, in_tablegroup))) {
LOG_WARN("failed to resolve range partition value node", K(ret));
} else if (OB_FAIL(resolve_partition_part_id(element_node->children_[PART_ID_NODE],
stmt,
max_used_subpart_id,
partition_num,
i,
subpart_id,
current_spec))) {
LOG_WARN("failed to resolve partition part id", K(ret));
} else {
if (0 == i) {
init_specified = current_spec;
} else if (current_spec != init_specified) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Should speicify part id for all parts", K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
}
}
// add range partition elements to table schema
if (OB_SUCC(ret)) {
subpartition.set_part_id(part_id);
subpartition.set_sub_part_id(subpart_id);
if (is_template) {
if (OB_FAIL(table_schema.add_def_subpartition(subpartition))) {
LOG_WARN("failed to add partition", K(ret));
}
} else if (OB_FAIL(partition->add_partition(subpartition))) {
LOG_WARN("failed to add partition", K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (is_template) {
table_schema.get_sub_part_option().set_part_num(partition_num);
} else {
partition->set_sub_part_num(partition_num);
}
}
}
return ret;
}
int ObDDLResolver::resolve_list_partition_elements(ObPartitionedStmt* stmt, ParseNode* node,
ObTableSchema& table_schema, const ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
ObDDLStmt::array_t& list_value_exprs, int64_t max_used_part_id, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
ParseNode* element_node = NULL;
ParseNode* expr_list_node = NULL;
if (OB_ISNULL(node) || OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(node), K(stmt));
} else if (max_used_part_id >= 0 && max_used_part_id < node->num_child_ - 1) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("max_used_part_id is invalid", K(ret), K(max_used_part_id), K(node->num_child_));
} else {
int64_t partition_num = node->num_child_;
ObPartition partition;
bool init_specified = false;
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
partition.reset();
ObString partition_name;
int64_t part_id = OB_INVALID_PARTITION_ID;
bool current_spec = false;
if (OB_ISNULL(element_node = node->children_[i]) ||
OB_ISNULL(expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpect node", K(ret), K(element_node), K(expr_list_node));
} else if (T_EXPR_LIST != expr_list_node->type_ && T_DEFAULT != expr_list_node->type_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected node type", K(ret), K(expr_list_node->type_));
} else if (OB_FAIL(
resolve_partition_name(element_node->children_[PARTITION_NAME_NODE], partition_name, partition))) {
LOG_WARN("failed to resolve partition name", K(ret));
} else if (OB_FAIL(resolve_list_partition_value_node(
*expr_list_node, partition_name, part_type, part_func_exprs, list_value_exprs, in_tablegroup))) {
LOG_WARN("failed to resolve list partiton value node", K(ret));
} else if (OB_FAIL(resolve_partition_part_id(element_node->children_[PART_ID_NODE],
stmt,
max_used_part_id,
partition_num,
i,
part_id,
current_spec))) {
LOG_WARN("failed to resolve partition part id", K(ret));
} else {
if (0 == i) {
init_specified = current_spec;
} else if (current_spec != init_specified) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Should speicify part id for all parts", K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
}
}
// add list partition elements to table schema
if (OB_SUCC(ret)) {
partition.set_part_id(part_id);
if (OB_FAIL(table_schema.check_part_id(partition))) {
LOG_WARN("failed to check part id", K(ret));
} else if (OB_FAIL(table_schema.add_partition(partition))) {
LOG_WARN("failed to add partition", K(ret));
} else if (table_schema.is_sub_part_template() &&
OB_NOT_NULL(element_node->children_[ELEMENT_SUBPARTITION_NODE])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("individual subpartition with sub part template", K(ret));
} else if (!table_schema.is_sub_part_template()) {
// resolve non template
ObPartition* cur_partition = table_schema.get_part_array()[i];
if (OB_ISNULL(cur_partition)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (OB_FAIL(resolve_subpartition_elements(stmt,
element_node->children_[ELEMENT_SUBPARTITION_NODE],
table_schema,
cur_partition,
false))) {
LOG_WARN("failed to resolve subpartition elements", K(ret));
}
}
}
}
if (OB_SUCC(ret)) {
table_schema.get_part_option().set_part_num(partition_num);
}
}
return ret;
}
int ObDDLResolver::resolve_list_subpartition_elements(ObPartitionedStmt* stmt, ParseNode* node,
ObTableSchema& table_schema, ObPartition* partition, const ObPartitionFuncType part_type,
const ObIArray<ObRawExpr*>& part_func_exprs, ObDDLStmt::array_t& list_value_exprs, int64_t max_used_subpart_id,
const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
ParseNode* element_node = NULL;
ParseNode* expr_list_node = NULL;
const bool is_template = table_schema.is_sub_part_template();
if (OB_ISNULL(node) || OB_ISNULL(stmt)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null or stmt is null", K(ret), K(node), K(stmt_));
} else if (max_used_subpart_id >= 0 && max_used_subpart_id < node->num_child_ - 1) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("max_used_subpart_id is invalid", K(ret), K(max_used_subpart_id), K(node->num_child_));
} else {
int64_t partition_num = node->num_child_;
ObSubPartition subpartition;
const int64_t part_id = is_template ? ObSubPartition::TEMPLATE_PART_ID : partition->get_part_id();
bool init_specified = false;
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; i++) {
subpartition.reset();
ObString partition_name;
int64_t subpart_id = OB_INVALID_ID;
bool current_spec = false;
if (OB_ISNULL(element_node = node->children_[i]) ||
OB_ISNULL(expr_list_node = element_node->children_[PARTITION_ELEMENT_NODE])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpect node", K(ret), K(element_node), K(expr_list_node));
} else if (T_EXPR_LIST != expr_list_node->type_ && T_DEFAULT != expr_list_node->type_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected node type", K(ret), K(expr_list_node->type_));
} else if (OB_FAIL(resolve_partition_name(
element_node->children_[PARTITION_NAME_NODE], partition_name, subpartition))) {
LOG_WARN("failed to resolve partition name", K(ret));
} else if (OB_FAIL(resolve_list_partition_value_node(
*expr_list_node, partition_name, part_type, part_func_exprs, list_value_exprs, in_tablegroup))) {
LOG_WARN("failed to resolve list partiton value node", K(ret));
} else if (OB_FAIL(resolve_partition_part_id(element_node->children_[PART_ID_NODE],
stmt,
max_used_subpart_id,
partition_num,
i,
subpart_id,
current_spec))) {
LOG_WARN("failed to resolve partition part id", K(ret));
} else {
if (0 == i) {
init_specified = current_spec;
} else if (current_spec != init_specified) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Should speicify part id for all parts", K(ret));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "partition id which should include either none or all partition ids");
}
}
// add list partition elements to table schema
if (OB_SUCC(ret)) {
subpartition.set_part_id(part_id);
subpartition.set_sub_part_id(subpart_id);
if (is_template) {
if (OB_FAIL(table_schema.add_def_subpartition(subpartition))) {
LOG_WARN("failed to add partition", K(ret));
}
} else if (OB_FAIL(partition->add_partition(subpartition))) {
LOG_WARN("failed to add partition", K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (is_template) {
table_schema.get_sub_part_option().set_part_num(partition_num);
} else {
partition->set_sub_part_num(partition_num);
}
}
}
return ret;
}
int ObDDLResolver::resolve_range_partition_value_node(ParseNode& expr_list_node, const ObString& partition_name,
const ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
ObIArray<ObRawExpr*>& range_value_exprs, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < expr_list_node.num_child_; ++i) {
if (OB_ISNULL(expr_list_node.children_[i])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get null node", K(ret));
} else if (T_NULL == expr_list_node.children_[i]->type_) {
ret = OB_EER_NULL_IN_VALUES_LESS_THAN;
LOG_WARN("null value is not allowed in less than", K(ret));
} else if (T_MAXVALUE == expr_list_node.children_[i]->type_) {
ObRawExpr* maxvalue_expr = NULL;
ObConstRawExpr* c_expr = NULL;
c_expr = (ObConstRawExpr*)allocator_->alloc(sizeof(ObConstRawExpr));
if (OB_ISNULL(c_expr)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allocate memory", K(ret));
} else {
c_expr = new (c_expr) ObConstRawExpr();
maxvalue_expr = c_expr;
maxvalue_expr->set_data_type(common::ObMaxType);
if (OB_FAIL(range_value_exprs.push_back(maxvalue_expr))) {
LOG_WARN("array push back fail", K(ret));
}
}
} else if (T_EXPR_LIST != expr_list_node.children_[i]->type_) {
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_,
*(expr_list_node.children_[i]),
partition_name,
part_type,
*part_func_expr,
part_value_expr,
in_tablegroup))) {
LOG_WARN("resolve partition expr failed", K(ret));
} else if (OB_FAIL(range_value_exprs.push_back(part_value_expr))) {
LOG_WARN("array push back fail", K(ret));
}
} else {
ret = OB_ERR_PARSER_SYNTAX;
LOG_WARN("syntax error, expect single expr while expr list got", K(ret));
}
}
return ret;
}
int ObDDLResolver::resolve_list_partition_value_node(ParseNode& expr_list_node, const ObString& partition_name,
const ObPartitionFuncType part_type, const ObIArray<ObRawExpr*>& part_func_exprs,
ObDDLStmt::array_t& list_value_exprs, const bool& in_tablegroup)
{
int ret = OB_SUCCESS;
ObOpRawExpr* row_expr = NULL;
if (OB_ISNULL(params_.expr_factory_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (OB_FAIL(params_.expr_factory_->create_raw_expr(T_OP_ROW, row_expr))) {
LOG_WARN("failed to create raw expr", K(ret));
} else if (OB_ISNULL(row_expr)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allcoate memory", K(ret));
} else if (T_DEFAULT == expr_list_node.type_) {
ObRawExpr* maxvalue_expr = NULL;
ObConstRawExpr* c_expr = NULL;
c_expr = (ObConstRawExpr*)allocator_->alloc(sizeof(ObConstRawExpr));
if (OB_ISNULL(c_expr)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allcoate memory", K(ret));
} else {
c_expr = new (c_expr) ObConstRawExpr();
maxvalue_expr = c_expr;
maxvalue_expr->set_data_type(common::ObMaxType);
if (OB_FAIL(row_expr->add_param_expr(maxvalue_expr))) {
LOG_WARN("failed add param expr", K(ret));
}
}
} else {
ObSEArray<ObRawExpr*, 16> part_value_exprs;
bool is_all_expr_list = false;
if (expr_list_node.num_child_ > 0) {
is_all_expr_list = (expr_list_node.children_[0]->type_ == T_EXPR_LIST);
}
for (int64_t i = 0; OB_SUCC(ret) && i < expr_list_node.num_child_; ++i) {
part_value_exprs.reset();
if ((is_all_expr_list && expr_list_node.children_[i]->type_ != T_EXPR_LIST) ||
(!is_all_expr_list && expr_list_node.children_[i]->type_ == T_EXPR_LIST)) {
ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
} else if (OB_ISNULL(expr_list_node.children_[i])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("node is null", K(ret));
} else if (OB_FAIL(ObResolverUtils::resolve_partition_list_value_expr(params_,
*(expr_list_node.children_[i]),
partition_name,
part_type,
part_func_exprs,
part_value_exprs,
in_tablegroup))) {
LOG_WARN("resolve partition expr failed", K(ret));
}
for (int64_t j = 0; OB_SUCC(ret) && j < part_value_exprs.count(); ++j) {
if (OB_FAIL(row_expr->add_param_expr(part_value_exprs.at(j)))) {
LOG_WARN("failed add param expr", K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (part_func_exprs.count() > 1 && !is_all_expr_list) {
if (row_expr->get_param_count() != part_func_exprs.count()) {
ret = OB_ERR_PARTITION_COLUMN_LIST_ERROR;
LOG_WARN("Inconsistency in usage of column lists for partitioning near", K(ret));
}
}
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(list_value_exprs.push_back(row_expr))) {
LOG_WARN("failed to push back expr", K(ret));
}
}
return ret;
}
int ObDDLResolver::generate_default_hash_part(
const int64_t partition_num, const int64_t max_used_part_id, ObTableSchema& table_schema)
{
int ret = OB_SUCCESS;
table_schema.get_part_option().set_part_num(partition_num);
char name_buf[common::OB_MAX_PARTITION_NAME_LENGTH];
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
ObPartition partition;
partition.set_part_id(max_used_part_id >= 0 ? max_used_part_id - partition_num + 1 + i : i);
partition.set_part_idx(i);
ObString part_name;
MEMSET(name_buf, 0, common::OB_MAX_PARTITION_NAME_LENGTH);
if (OB_FAIL(table_schema.gen_hash_part_name(partition.get_part_idx(),
ObHashNameType::FIRST_PART,
is_oracle_mode(),
name_buf,
common::OB_MAX_PARTITION_NAME_LENGTH,
NULL))) {
LOG_WARN("failed to gen hash part name", K(ret));
} else if (FALSE_IT(part_name = ObString(strlen(name_buf), name_buf))) {
} else if (OB_FAIL(partition.set_part_name(part_name))) {
LOG_WARN("fail to set part name", K(ret));
} else if (OB_FAIL(table_schema.check_part_name(partition))) {
LOG_WARN("fail to check part name", K(ret));
} else if (OB_FAIL(table_schema.add_partition(partition))) {
LOG_WARN("fail to add partition", K(ret));
}
}
return ret;
}
int ObDDLResolver::generate_default_hash_subpart(
const int64_t partition_num, const int64_t max_used_subpart_id, ObTableSchema& table_schema, ObPartition* partition)
{
int ret = OB_SUCCESS;
char name_buf[common::OB_MAX_PARTITION_NAME_LENGTH];
const bool is_template = table_schema.is_sub_part_template();
if (!is_template && OB_ISNULL(partition)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("table is not subpart template by partition is null", K(ret));
} else if (is_template) {
table_schema.get_sub_part_option().set_part_num(partition_num);
} else {
partition->set_sub_part_num(partition_num);
}
if (OB_SUCC(ret)) {
const int64_t part_id = is_template ? ObSubPartition::TEMPLATE_PART_ID : partition->get_part_id();
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
ObSubPartition subpartition;
subpartition.set_part_id(part_id);
subpartition.set_sub_part_id(max_used_subpart_id >= 0 ? max_used_subpart_id - partition_num + 1 + i : i);
subpartition.set_sub_part_idx(i);
ObString subpart_name;
MEMSET(name_buf, 0, common::OB_MAX_PARTITION_NAME_LENGTH);
if (is_template && OB_FAIL(table_schema.gen_hash_part_name(subpartition.get_sub_part_idx(),
ObHashNameType::TEMPLATE_SUB_PART,
is_oracle_mode(),
name_buf,
common::OB_MAX_PARTITION_NAME_LENGTH,
NULL))) {
LOG_WARN("faield to gen hash part name", K(ret));
} else if (!is_template && OB_FAIL(table_schema.gen_hash_part_name(subpartition.get_sub_part_idx(),
ObHashNameType::INDIVIDUAL_SUB_PART,
is_oracle_mode(),
name_buf,
common::OB_MAX_PARTITION_NAME_LENGTH,
NULL,
partition))) {
LOG_WARN("faield to gen hash part name", K(ret));
} else if (FALSE_IT(subpart_name = ObString(strlen(name_buf), name_buf))) {
} else if (OB_FAIL(subpartition.set_part_name(subpart_name))) {
LOG_WARN("fail to set part name", K(ret));
} else if (is_template) {
if (OB_FAIL(table_schema.add_def_subpartition(subpartition))) {
LOG_WARN("fail to add partition", K(ret));
}
} else if (OB_FAIL(partition->add_partition(subpartition))) {
LOG_WARN("failed to add partition", K(ret));
}
}
}
return ret;
}
int ObDDLResolver::check_and_set_partition_names(ObPartitionedStmt* stmt, ObTableSchema& table_schema)
{
int ret = OB_SUCCESS;
if (OB_FAIL(check_and_set_partition_names(stmt, table_schema, false))) {
LOG_WARN("failed to check and set partition names", K(ret));
} else if (PARTITION_LEVEL_TWO == table_schema.get_part_level()) {
if (table_schema.is_sub_part_template()) {
if (OB_FAIL(check_and_set_partition_names(stmt, table_schema, true))) {
LOG_WARN("failed to check and set partition names", K(ret));
}
} else if (OB_FAIL(check_and_set_individual_subpartition_names(stmt, table_schema))) {
LOG_WARN("failed to check and set individual subpartition names", K(ret));
}
}
return ret;
}
int ObDDLResolver::check_and_set_partition_names(ObPartitionedStmt* stmt, ObTableSchema& table_schema, bool is_subpart)
{
int ret = OB_SUCCESS;
hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>* partition_name_set = nullptr;
void* buf = nullptr;
int64_t partition_num = is_subpart ? table_schema.get_def_sub_part_num() : table_schema.get_first_part_num();
ObBasePartition* partition = NULL;
ObPartition** partition_array = table_schema.get_part_array();
ObSubPartition** subpartition_array = table_schema.get_def_subpart_array();
ObSEArray<int64_t, 128> empty_part_idx;
if (is_subpart && OB_ISNULL(subpartition_array)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get null subpartition array", K(ret));
} else if (!is_subpart && OB_ISNULL(partition_array)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get null partition array", K(ret));
} else if (OB_ISNULL(buf = allocator_->alloc(sizeof(
hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("fail to allocate memory", KR(ret));
} else {
partition_name_set = new (buf) hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>();
if (OB_ISNULL(partition_name_set)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition name hash set is null", KR(ret));
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
if (is_subpart) {
partition = subpartition_array[i];
} else {
partition = partition_array[i];
}
if (OB_ISNULL(partition)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (partition->is_empty_partition_name()) {
if (OB_FAIL(empty_part_idx.push_back(i))) {
LOG_WARN("failed to push back part idx", K(ret));
}
} else {
const ObString& partition_name = partition->get_part_name();
ObPartitionNameHashWrapper partition_name_key(partition_name);
if (OB_HASH_EXIST == partition_name_set->exist_refactored(partition_name_key)) {
ret = OB_ERR_SAME_NAME_PARTITION;
LOG_USER_ERROR(OB_ERR_SAME_NAME_PARTITION, partition_name.length(), partition_name.ptr());
} else if (OB_FAIL(partition_name_set->set_refactored(partition_name_key))) {
LOG_WARN("add partition name to map failed", K(ret), K(ret));
}
}
}
if (OB_SUCC(ret) && !empty_part_idx.empty() &&
(stmt::T_CREATE_TABLE == stmt->get_stmt_type() || stmt::T_CREATE_TABLEGROUP == stmt->get_stmt_type() ||
stmt::T_CREATE_INDEX == stmt->get_stmt_type())) {
int64_t max_part_id = OB_MAX_PARTITION_NUM_MYSQL;
ObString part_name_str;
for (int64_t i = 0; OB_SUCC(ret) && i < empty_part_idx.count(); ++i) {
const int64_t part_idx = empty_part_idx.at(i);
if (is_subpart) {
partition = subpartition_array[part_idx];
} else {
partition = partition_array[part_idx];
}
bool is_valid = false;
while (OB_SUCC(ret) && !is_valid) {
char part_name[OB_MAX_PARTITION_NAME_LENGTH];
int64_t pos = 0;
if (OB_FAIL(databuff_printf(part_name, OB_MAX_PARTITION_NAME_LENGTH, pos, "P%ld", max_part_id))) {
LOG_WARN("failed to print databuff", K(ret), K(max_part_id));
} else {
part_name_str.assign(part_name, static_cast<int32_t>(pos));
ObPartitionNameHashWrapper partition_name_key(part_name_str);
if (OB_HASH_EXIST == partition_name_set->exist_refactored(partition_name_key)) {
// do nothing
} else if (OB_FAIL(partition_name_set->set_refactored(partition_name_key))) {
LOG_WARN("add partition name to map failed", K(ret), K(ret));
} else if (OB_FAIL(partition->set_part_name(part_name_str))) {
LOG_WARN("failed to set part name", K(ret));
} else {
partition->set_is_empty_partition_name(false);
is_valid = true;
}
}
++max_part_id;
}
}
}
return ret;
}
int ObDDLResolver::check_and_set_individual_subpartition_names(ObPartitionedStmt* stmt, ObTableSchema& table_schema)
{
int ret = OB_SUCCESS;
hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>* partition_name_set = nullptr;
void* buf = nullptr;
int64_t partition_num = table_schema.get_first_part_num();
ObPartition** partition_array = NULL;
ObPartition* partition = NULL;
ObSubPartition** subpartition_array = NULL;
ObSubPartition* subpartition = NULL;
ObSEArray<int64_t, 128> empty_part_idx;
ObSEArray<int64_t, 128> empty_subpart_idx;
if (OB_UNLIKELY(table_schema.is_sub_part_template())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected subpartition", K(ret));
} else if (OB_ISNULL(partition_array = table_schema.get_part_array())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (OB_ISNULL(buf = allocator_->alloc(sizeof(
hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("fail to allocate memory", KR(ret));
} else {
partition_name_set = new (buf) hash::ObPlacementHashSet<ObPartitionNameHashWrapper, OB_MAX_PARTITION_NUM_ORACLE>();
if (OB_ISNULL(partition_name_set)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("partition name hash set is null", KR(ret));
}
}
for (int64_t i = 0; OB_SUCC(ret) && i < partition_num; ++i) {
if (OB_ISNULL(partition = partition_array[i]) || OB_ISNULL(subpartition_array = partition->get_subpart_array())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(partition), K(subpartition_array));
}
for (int64_t j = 0; OB_SUCC(ret) && j < partition->get_sub_part_num(); ++j) {
if (OB_ISNULL(subpartition = subpartition_array[j])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret));
} else if (subpartition->is_empty_partition_name()) {
if (OB_FAIL(empty_part_idx.push_back(i))) {
LOG_WARN("failed to push back part idx", K(ret));
} else if (OB_FAIL(empty_subpart_idx.push_back(j))) {
LOG_WARN("failed to push back subpart idx", K(ret));
}
} else {
const ObString& partition_name = subpartition->get_part_name();
ObPartitionNameHashWrapper partition_name_key(partition_name);
if (OB_HASH_EXIST == partition_name_set->exist_refactored(partition_name_key)) {
ret = OB_ERR_SAME_NAME_SUBPARTITION;
LOG_USER_ERROR(OB_ERR_SAME_NAME_SUBPARTITION, partition_name.length(), partition_name.ptr());
} else if (OB_FAIL(partition_name_set->set_refactored(partition_name_key))) {
LOG_WARN("add partition name to map failed", K(ret), K(ret));
}
}
}
}
if (!empty_part_idx.empty() &&
(stmt::T_CREATE_TABLE == stmt->get_stmt_type() || stmt::T_CREATE_TABLEGROUP == stmt->get_stmt_type() ||
stmt::T_CREATE_INDEX == stmt->get_stmt_type())) {
int64_t max_part_id = OB_MAX_PARTITION_NUM_MYSQL;
ObString part_name_str;
for (int64_t i = 0; OB_SUCC(ret) && i < empty_part_idx.count(); ++i) {
int64_t part_idx = empty_part_idx.at(i);
int64_t subpart_idx = empty_subpart_idx.at(i);
subpartition = partition_array[part_idx]->get_subpart_array()[subpart_idx];
bool is_valid = false;
while (OB_SUCC(ret) && !is_valid) {
char part_name[OB_MAX_PARTITION_NAME_LENGTH];
int64_t pos = 0;
if (OB_FAIL(databuff_printf(part_name, OB_MAX_PARTITION_NAME_LENGTH, pos, "P%ld", max_part_id))) {
LOG_WARN("failed to print databuff", K(ret), K(max_part_id));
} else {
part_name_str.assign(part_name, static_cast<int32_t>(pos));
ObPartitionNameHashWrapper partition_name_key(part_name_str);
if (OB_HASH_EXIST == partition_name_set->exist_refactored(partition_name_key)) {
// do nothing
} else if (OB_FAIL(partition_name_set->set_refactored(partition_name_key))) {
LOG_WARN("add partition name to map failed", K(ret), K(ret));
} else if (OB_FAIL(subpartition->set_part_name(part_name_str))) {
LOG_WARN("failed to set part name", K(ret));
} else {
subpartition->set_is_empty_partition_name(false);
is_valid = true;
}
}
++max_part_id;
}
}
}
return ret;
}
int ObDDLResolver::check_individual_subpartition_define(ObPartitionedStmt* stmt, ObTableSchema& table_schema)
{
int ret = OB_SUCCESS;
int64_t partition_num = table_schema.get_first_part_num();
ObPartition** partition_array = NULL;
ObPartition* partition = NULL;
bool need_check_value = table_schema.is_range_subpart() || table_schema.is_list_subpart();
if (OB_ISNULL(stmt) || OB_ISNULL(partition_array = table_schema.get_part_array())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(stmt), K(partition_array));
} else if (OB_UNLIKELY(table_schema.is_sub_part_template())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected subpartition", K(ret), K(table_schema.is_sub_part_template()));
} else if (need_check_value && partition_num != stmt->get_individual_subpart_values_exprs().count()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected subpartition value exprs",
K(ret),
K(partition_num),
K(stmt->get_individual_subpart_values_exprs()));
} else if (partition_num <= 1) {
// do nothing
} else if (OB_ISNULL(partition = partition_array[0])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(partition));
} else {
const int64_t first_subpart_number = partition->get_sub_part_num();
const ObIArray<ObRawExpr*>* first_subpart_value_exprs = NULL;
if (need_check_value) {
first_subpart_value_exprs = &(stmt->get_individual_subpart_values_exprs().at(0));
}
for (int64_t i = 1; OB_SUCC(ret) && i < partition_num; ++i) {
if (OB_ISNULL(partition = partition_array[i])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(partition));
} else if (first_subpart_number != partition->get_sub_part_num()) {
ret = OB_NOT_SUPPORTED;
LOG_USER_ERROR(OB_NOT_SUPPORTED, "individual subpartition with different define");
} else if (need_check_value) {
const ObIArray<ObRawExpr*>& cur_value_exprs = stmt->get_individual_subpart_values_exprs().at(i);
const ObRawExpr* l_expr = NULL;
const ObRawExpr* r_expr = NULL;
for (int64_t j = 0; OB_SUCC(ret) && j < first_subpart_value_exprs->count(); ++j) {
if (OB_ISNULL(l_expr = first_subpart_value_exprs->at(j)) || OB_ISNULL(r_expr = cur_value_exprs.at(j))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("get unexpected null", K(ret), K(l_expr), K(r_expr));
} else if (!l_expr->same_as(*r_expr)) {
ret = OB_NOT_SUPPORTED;
LOG_USER_ERROR(OB_NOT_SUPPORTED, "individual subpartition with different define");
}
}
}
}
}
return ret;
}
int ObDDLResolver::check_max_used_subpart_id_valid(
const share::schema::ObTableSchema& table_schema, const ObPartition& partition, int64_t& max_used_subpart_id)
{
int ret = OB_SUCCESS;
int64_t current_max_subpart_id = -1;
const int64_t subpart_num = partition.get_sub_part_num();
if (table_schema.is_range_subpart() || table_schema.is_list_subpart()) {
ObSubPartition** subpart_array = partition.get_subpart_array();
const int64_t subpart_idx = subpart_num - 1;
if (subpart_idx < 0) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Invalid part idx", K(ret));
} else if (OB_ISNULL(subpart_array)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("Empty partition", K(ret));
} else if (OB_ISNULL(subpart_array[subpart_idx])) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("NULL ptr", K(ret));
} else if (subpart_array[subpart_idx]->get_sub_part_id() < 0) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Invalid part id", K(ret), K(subpart_idx), K(subpart_array[subpart_idx]->get_sub_part_id()));
} else {
current_max_subpart_id = subpart_array[subpart_idx]->get_sub_part_id();
}
} else {
current_max_subpart_id = subpart_num - 1;
}
if (OB_SUCC(ret)) {
if (max_used_subpart_id < 0) {
max_used_subpart_id = current_max_subpart_id;
} else if (PARTITION_LEVEL_ZERO == table_schema.get_part_level() ||
PARTITION_LEVEL_ONE == table_schema.get_part_level()) {
ret = OB_NOT_SUPPORTED;
SQL_RESV_LOG(WARN, "non subpart table with max_used_sub_part_id not support", K(ret), K(current_max_subpart_id));
LOG_USER_ERROR(OB_NOT_SUPPORTED, "non subpart table with max_used_sub_part_id");
} else if (max_used_subpart_id < current_max_subpart_id) {
ret = OB_INVALID_ARGUMENT;
SQL_RESV_LOG(WARN, "invalid max_used_subpart_id", K(ret), K(max_used_subpart_id), K(current_max_subpart_id));
LOG_USER_ERROR(OB_INVALID_ARGUMENT, "max_used_subpart_id");
} else {
// use max_used_part_id_
}
}
return ret;
}
} // namespace sql
} // namespace oceanbase