patch 4.0

This commit is contained in:
wangzelin.wzl
2022-10-24 10:34:53 +08:00
parent 4ad6e00ec3
commit 93a1074b0c
10533 changed files with 2588271 additions and 2299373 deletions

View File

@ -12,93 +12,132 @@
#define USING_LOG_PREFIX SQL_ENG
#include "ob_expr_calc_partition_id.h"
#include "share/part/ob_part_mgr_ad.h"
#include "sql/code_generator/ob_static_engine_expr_cg.h"
#include "sql/resolver/expr/ob_raw_expr.h"
#include "sql/engine/ob_exec_context.h"
#include "sql/engine/expr/ob_expr_func_part_hash.h"
#include "sql/engine/expr/ob_expr_calc_partition_id.h"
namespace oceanbase {
namespace oceanbase
{
using namespace common;
using namespace share::schema;
namespace sql {
namespace sql
{
OB_SERIALIZE_MEMBER(
CalcPartitionIdInfo, ref_table_id_, part_level_, part_type_, subpart_type_, part_num_, subpart_num_);
OB_SERIALIZE_MEMBER(CalcPartitionBaseInfo,
ref_table_id_,
related_table_ids_,
part_level_,
part_type_,
subpart_type_,
part_num_,
subpart_num_,
partition_id_calc_type_,
may_add_interval_part_,
calc_id_type_);
int CalcPartitionIdInfo::deep_copy(
common::ObIAllocator& allocator, const ObExprOperatorType type, ObIExprExtraInfo*& copied_info) const
int CalcPartitionBaseInfo::deep_copy(common::ObIAllocator &allocator,
const ObExprOperatorType type,
ObIExprExtraInfo *&copied_info) const
{
int ret = OB_SUCCESS;
if (OB_FAIL(ObExprExtraInfoFactory::alloc(allocator, type, copied_info))) {
if (OB_FAIL(ObExprExtraInfoFactory::alloc(allocator, type,
copied_info))) {
LOG_WARN("failed to alloc extra info", K(ret));
} else {
*copied_info = *this;
CalcPartitionBaseInfo *base_info = static_cast<CalcPartitionBaseInfo*>(copied_info);
if (OB_FAIL(base_info->related_table_ids_.assign(related_table_ids_))) {
LOG_WARN("assign related table ids failed", K(ret));
} else {
base_info->ref_table_id_ = ref_table_id_;
base_info->part_level_ = part_level_;
base_info->part_type_ = part_type_;
base_info->subpart_type_ = subpart_type_;
base_info->part_num_ = part_num_;
base_info->subpart_num_ = subpart_num_;
base_info->partition_id_calc_type_ = partition_id_calc_type_;
base_info->may_add_interval_part_ = may_add_interval_part_;
base_info->calc_id_type_ = calc_id_type_;
base_info->first_part_id_ = first_part_id_;
}
}
return ret;
}
ObExprCalcPartitionId::ObExprCalcPartitionId(ObIAllocator& alloc)
: ObFuncExprOperator(alloc, T_FUN_SYS_CALC_PARTITION_ID, N_CALC_PARTITION_ID, PARAM_NUM_UNKNOWN, NOT_ROW_DIMENSION)
{}
int ObExprCalcPartitionBase::set_may_add_interval_part(ObExpr *expr,
const MayAddIntervalPart info)
{
int ret = OB_SUCCESS;
CalcPartitionBaseInfo *calc_part_info = NULL;
CK (OB_NOT_NULL(expr));
OX (calc_part_info = reinterpret_cast<CalcPartitionBaseInfo *>(expr->extra_info_));
CK (OB_NOT_NULL(calc_part_info));
OX (calc_part_info->may_add_interval_part_ = info);
return ret;
}
ObExprCalcPartitionId::~ObExprCalcPartitionId()
{}
int ObExprCalcPartitionId::calc_result_typeN(
ObExprResType& type, ObExprResType* types_array, int64_t param_num, common::ObExprTypeCtx& type_ctx) const
int ObExprCalcPartitionBase::calc_result_typeN(ObExprResType &type,
ObExprResType *types_array,
int64_t param_num,
common::ObExprTypeCtx &type_ctx) const
{
UNUSED(types_array);
UNUSED(param_num);
UNUSED(type_ctx);
type.set_int();
type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObIntType].precision_);
type.set_scale(DEFAULT_SCALE_FOR_INTEGER);
if (CALC_PARTITION_TABLET_ID == get_calc_id_type()) {
type.set_binary();
type.set_length(sizeof(uint64_t) * 2);
} else {
type.set_int();
type.set_precision(ObAccuracy::DDL_DEFAULT_ACCURACY[ObIntType].precision_);
type.set_scale(DEFAULT_SCALE_FOR_INTEGER);
}
return OB_SUCCESS;
}
int ObExprCalcPartitionId::cg_expr(ObExprCGCtx& expr_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const
int ObExprCalcPartitionBase::cg_expr(ObExprCGCtx &expr_cg_ctx,
const ObRawExpr &raw_expr,
ObExpr &rt_expr) const
{
int ret = OB_SUCCESS;
uint64_t ref_table_id = raw_expr.get_extra();
CalcPartitionIdInfo* calc_part_info = NULL;
const ObTableSchema* table_schema = NULL;
ObSqlCtx* sql_ctx = NULL;
;
ObTableID ref_table_id = reinterpret_cast<ObTableID>(raw_expr.get_extra());
CalcPartitionBaseInfo *calc_part_info = NULL;
const ObTableSchema *table_schema = NULL;
OptRouteType opt_route = OPT_ROUTE_NONE;
if (OB_ISNULL(expr_cg_ctx.exec_ctx_) || OB_ISNULL(sql_ctx = expr_cg_ctx.exec_ctx_->get_sql_ctx()) ||
OB_ISNULL(sql_ctx->schema_guard_)) {
if (OB_ISNULL(expr_cg_ctx.schema_guard_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(ret), KP(expr_cg_ctx.exec_ctx_));
LOG_WARN("invalid argument", K(ret));
} else if (0 == ref_table_id) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid ref table id", K(ref_table_id), K(ret));
} else if (OB_FAIL(sql_ctx->schema_guard_->get_table_schema(ref_table_id, table_schema))) {
} else if (OB_FAIL(expr_cg_ctx.schema_guard_->get_table_schema(
MTL_ID(), ref_table_id, table_schema))) {
LOG_WARN("fail to get table schema", K(ref_table_id), K(ret));
} else if (OB_ISNULL(table_schema)) {
ret = OB_TABLE_NOT_EXIST;
LOG_WARN("Table not exist", K(ref_table_id), K(ret));
} else if (OB_FAIL(init_calc_part_info(expr_cg_ctx, *table_schema, calc_part_info))) {
} else if (OB_FAIL(init_calc_part_info(expr_cg_ctx.allocator_,
*table_schema,
raw_expr.get_partition_id_calc_type(),
raw_expr.get_may_add_interval_part(),
calc_part_info))) {
LOG_WARN("fail to init tl expr info", K(ret));
} else if (OB_ISNULL(calc_part_info)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("fail to init tl expr info", K(ret), K(calc_part_info));
} else if (OB_FAIL(get_opt_route(*table_schema, raw_expr, opt_route))) {
LOG_WARN("fail to check use opt", K(ret));
} else {
rt_expr.extra_info_ = calc_part_info;
int64_t param_cnt = raw_expr.get_param_count();
if (OPT_ROUTE_HASH_ONE == opt_route) {
rt_expr.eval_func_ = ObExprCalcPartitionId::calc_opt_route_hash_one;
} else if (0 == param_cnt) {
if (0 == param_cnt) {
OB_ASSERT(PARTITION_LEVEL_ZERO == calc_part_info->part_level_);
rt_expr.eval_func_ = ObExprCalcPartitionId::calc_no_partition_location;
rt_expr.eval_func_ = ObExprCalcPartitionBase::calc_no_partition_location;
} else if (1 == param_cnt) {
OB_ASSERT(PARTITION_LEVEL_ONE == calc_part_info->part_level_);
rt_expr.eval_func_ = ObExprCalcPartitionId::calc_partition_level_one;
rt_expr.eval_func_ = ObExprCalcPartitionBase::calc_partition_level_one;
} else if (2 == param_cnt) {
OB_ASSERT(PARTITION_LEVEL_TWO == calc_part_info->part_level_);
rt_expr.eval_func_ = ObExprCalcPartitionId::calc_partition_level_two;
rt_expr.eval_func_ = ObExprCalcPartitionBase::calc_partition_level_two;
} else {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid param cnt", K(ret), K(param_cnt));
@ -108,97 +147,72 @@ int ObExprCalcPartitionId::cg_expr(ObExprCGCtx& expr_cg_ctx, const ObRawExpr& ra
return ret;
}
int ObExprCalcPartitionId::init_calc_part_info(
ObExprCGCtx& expr_cg_ctx, const ObTableSchema& table_schema, CalcPartitionIdInfo*& calc_part_info)
int ObExprCalcPartitionBase::init_calc_part_info(ObIAllocator *allocator,
const ObTableSchema &table_schema,
PartitionIdCalcType calc_type,
MayAddIntervalPart add_part,
CalcPartitionBaseInfo *&calc_part_info) const
{
int ret = OB_SUCCESS;
calc_part_info = NULL;
CK(OB_NOT_NULL(expr_cg_ctx.allocator_));
CK(OB_NOT_NULL(allocator));
if (OB_SUCC(ret)) {
void* buf = expr_cg_ctx.allocator_->alloc(sizeof(CalcPartitionIdInfo));
void *buf = allocator->alloc(sizeof(CalcPartitionBaseInfo));
if (OB_ISNULL(buf)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("fail to alloc memory", K(ret));
} else {
calc_part_info = new (buf) CalcPartitionIdInfo(*expr_cg_ctx.allocator_, T_FUN_SYS_CALC_PARTITION_ID);
calc_part_info = new(buf) CalcPartitionBaseInfo(*allocator, get_type());
calc_part_info->ref_table_id_ = table_schema.get_table_id();
calc_part_info->part_level_ = table_schema.get_part_level();
calc_part_info->part_type_ = table_schema.get_part_option().get_part_func_type();
calc_part_info->subpart_type_ = table_schema.get_sub_part_option().get_sub_part_func_type();
calc_part_info->part_num_ = table_schema.get_first_part_num();
calc_part_info->subpart_num_ = OB_INVALID_ID; // unsed for now
LOG_DEBUG("table location expr info", K(*calc_part_info), K(ret));
calc_part_info->subpart_num_ = OB_INVALID_ID; // 目前未使用,要使用的话需要考虑二级分区个数异构
calc_part_info->partition_id_calc_type_ = calc_type;
calc_part_info->may_add_interval_part_ = add_part;
calc_part_info->calc_id_type_ = get_calc_id_type();
LOG_DEBUG("table location expr info", KPC(calc_part_info), K(ret));
}
}
return ret;
}
int ObExprCalcPartitionId::calc_no_partition_location(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res_datum)
int ObExprCalcPartitionBase::calc_no_partition_location(const ObExpr &expr,
ObEvalCtx &ctx,
ObDatum &res_datum)
{
int ret = OB_SUCCESS;
UNUSED(expr);
UNUSED(ctx);
res_datum.set_int(0);
return ret;
}
int ObExprCalcPartitionId::calc_partition_level_one(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res_datum)
{
int ret = OB_SUCCESS;
OB_ASSERT(1 == expr.arg_cnt_);
OB_ASSERT(expr.extra_ > 0);
CalcPartitionIdInfo* calc_part_info = reinterpret_cast<CalcPartitionIdInfo*>(expr.extra_);
if (OB_FAIL(calc_partition_id(*expr.args_[0],
ctx,
*calc_part_info,
NONE_PARTITION_ID, /*first_part_id*/
res_datum))) {
LOG_WARN("fail to calc partitoin id", K(ret));
}
return ret;
}
int ObExprCalcPartitionId::calc_partition_level_two(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res_datum)
{
int ret = OB_SUCCESS;
OB_ASSERT(2 == expr.arg_cnt_);
OB_ASSERT(expr.extra_ > 0);
CalcPartitionIdInfo* calc_part_info = reinterpret_cast<CalcPartitionIdInfo*>(expr.extra_);
PartitionIdCalcType calc_type = ctx.exec_ctx_.get_partition_id_calc_type();
if (CALC_IGNORE_FIRST_PART == calc_type) {
int64_t first_part_id = ctx.exec_ctx_.get_fixed_id();
if (OB_FAIL(calc_partition_id(*expr.args_[1], ctx, *calc_part_info, first_part_id, res_datum))) {
LOG_WARN("fail to calc partitoin id", K(ret));
}
} else if (CALC_IGNORE_SUB_PART == calc_type) {
if (OB_FAIL(calc_partition_id(*expr.args_[0],
ctx,
*calc_part_info,
NONE_PARTITION_ID, /*first_part_id*/
res_datum))) {
LOG_WARN("fail to calc partitoin id", K(ret));
}
} else if (OB_FAIL(calc_partition_id(*expr.args_[0],
ctx,
*calc_part_info,
NONE_PARTITION_ID, /*first_part_id*/
res_datum))) {
LOG_WARN("fail to calc partitoin id", K(ret));
ObDASTabletMapper tablet_mapper;
ObSEArray<ObTabletID, 1> tablet_ids;
ObSEArray<ObObjectID, 1> partition_ids;
CalcPartitionBaseInfo *calc_part_info = reinterpret_cast<CalcPartitionBaseInfo *>(expr.extra_info_);
if (OB_FAIL(ctx.exec_ctx_.get_das_ctx().get_das_tablet_mapper(calc_part_info->ref_table_id_,
tablet_mapper,
&calc_part_info->related_table_ids_))) {
LOG_WARN("get das tablet mapper failed", K(ret), K(calc_part_info));
} else if (OB_FAIL(tablet_mapper.get_non_partition_tablet_id(tablet_ids, partition_ids))) {
LOG_WARN("fail to get non partition tablet id", K(ret));
} else {
int64_t first_part_id = res_datum.get_int();
if (NONE_PARTITION_ID == first_part_id) {
// do nothing
// The first level partition is not calculated, return NONE_PARTITION_ID
} else {
if (OB_FAIL(calc_partition_id(*expr.args_[1], ctx, *calc_part_info, first_part_id, res_datum))) {
LOG_WARN("fail to calc partitoin id", K(ret));
} else if (NONE_PARTITION_ID == res_datum.get_int()) {
// do nothing
if (CALC_TABLET_ID == calc_part_info->calc_id_type_) {
if (0 == tablet_ids.count()) {
res_datum.set_int(ObTabletID::INVALID_TABLET_ID);
} else {
res_datum.set_int(generate_phy_part_id(first_part_id, res_datum.get_int(), PARTITION_LEVEL_TWO));
res_datum.set_int(tablet_ids.at(0).id());
}
} else if (CALC_PARTITION_ID == calc_part_info->calc_id_type_) {
if (0 == partition_ids.count()) {
res_datum.set_int(OB_INVALID_ID);
} else {
res_datum.set_int(partition_ids.at(0));
}
} else if (CALC_PARTITION_TABLET_ID == calc_part_info->calc_id_type_) {
if (OB_FAIL(concat_part_and_tablet_id(expr, ctx, res_datum,
(0 == partition_ids.count()) ? OB_INVALID_ID : partition_ids.at(0),
(0 == tablet_ids.count()) ? OB_INVALID_ID : tablet_ids.at(0).id()))) {
LOG_WARN("fail to concat partition id and tablet id", K(ret));
}
}
}
@ -206,12 +220,177 @@ int ObExprCalcPartitionId::calc_partition_level_two(const ObExpr& expr, ObEvalCt
return ret;
}
int ObExprCalcPartitionId::build_row(ObEvalCtx& ctx, ObIAllocator& allocator, const ObExpr& expr, ObNewRow& row)
int ObExprCalcPartitionBase::calc_partition_level_one(const ObExpr &expr,
ObEvalCtx &ctx,
ObDatum &res_datum)
{
int ret = OB_SUCCESS;
OB_ASSERT(1 == expr.arg_cnt_);
CalcPartitionBaseInfo *calc_part_info = reinterpret_cast<CalcPartitionBaseInfo *>(expr.extra_info_);
CK (OB_NOT_NULL(calc_part_info));
ObTabletID tablet_id(ObTabletID::INVALID_TABLET_ID);
ObObjectID partition_id = OB_INVALID_ID;
OZ (calc_partition_id(*expr.args_[0],
ctx,
*calc_part_info,
OB_INVALID_ID, /*first_part_id*/
tablet_id,
partition_id));
if (OB_SUCC(ret)) {
if (CALC_TABLET_ID == calc_part_info->calc_id_type_) {
res_datum.set_int(tablet_id.id());
} else if (CALC_PARTITION_ID == calc_part_info->calc_id_type_) {
res_datum.set_int(partition_id);
} else if (CALC_PARTITION_TABLET_ID == calc_part_info->calc_id_type_) {
if (OB_FAIL(concat_part_and_tablet_id(expr, ctx, res_datum, partition_id, tablet_id.id()))) {
LOG_WARN("fail to concat partition id and tablet id", K(ret));
}
}
}
return ret;
}
int ObExprCalcPartitionBase::calc_partition_level_two(const ObExpr &expr,
ObEvalCtx &ctx,
ObDatum &res_datum)
{
int ret = OB_SUCCESS;
OB_ASSERT(2 == expr.arg_cnt_);
OB_ASSERT(nullptr != expr.extra_info_);
CalcPartitionBaseInfo *calc_part_info = reinterpret_cast<CalcPartitionBaseInfo *>(expr.extra_info_);
PartitionIdCalcType calc_type = CALC_INVALID == calc_part_info->partition_id_calc_type_ ?
ctx.exec_ctx_.get_partition_id_calc_type() :
calc_part_info->partition_id_calc_type_;
ObObjectID first_part_id = OB_INVALID_ID;
ObTabletID tablet_id(ObTabletID::INVALID_TABLET_ID);
ObObjectID partition_id = OB_INVALID_ID;
if (CALC_IGNORE_FIRST_PART == calc_type) {
if (OB_FAIL(calc_partition_id(*expr.args_[1],
ctx,
*calc_part_info,
calc_part_info->first_part_id_,
tablet_id,
partition_id))) {
LOG_WARN("fail to calc partitoin id", K(ret));
}
} else if (CALC_IGNORE_SUB_PART == calc_type) {
if (OB_FAIL(calc_partition_id(*expr.args_[0],
ctx,
*calc_part_info,
OB_INVALID_ID, /*first_part_id*/
tablet_id,
partition_id))) {
LOG_WARN("fail to calc partitoin id", K(ret));
} else {
// FIXME @YISHEN
tablet_id = ObTabletID(partition_id);
}
} else if (OB_FAIL(calc_partition_id(*expr.args_[0],
ctx,
*calc_part_info,
OB_INVALID_ID, /*first_part_id*/
tablet_id,
first_part_id))) {
LOG_WARN("fail to calc partitoin id", K(ret));
} else {
if (OB_INVALID_ID == first_part_id) {
// do nothing
} else {
if (OB_FAIL(calc_partition_id(*expr.args_[1],
ctx,
*calc_part_info,
first_part_id,
tablet_id,
partition_id))) {
LOG_WARN("fail to calc partitoin id", K(ret));
}
}
}
if (OB_SUCC(ret)) {
if (CALC_TABLET_ID == calc_part_info->calc_id_type_) {
res_datum.set_int(tablet_id.id());
} else if (CALC_PARTITION_ID == calc_part_info->calc_id_type_) {
res_datum.set_int(partition_id);
} else if (CALC_PARTITION_TABLET_ID == calc_part_info->calc_id_type_) {
if (OB_FAIL(concat_part_and_tablet_id(expr, ctx, res_datum, partition_id, tablet_id.id()))) {
LOG_WARN("fail to concat partition id and tablet id", K(ret));
}
}
}
return ret;
}
int ObExprCalcPartitionBase::concat_part_and_tablet_id(const ObExpr &expr,
ObEvalCtx &ctx,
ObDatum &res_datum,
uint64_t partition_id,
uint64_t tablet_id)
{
int ret = OB_SUCCESS;
uint64_t buf_len = sizeof(uint64_t) * 2;
uint64_t *buf = reinterpret_cast<uint64_t *>(expr.get_str_res_mem(ctx, buf_len));
if (OB_ISNULL(buf)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("fail to alloc memory", K(ret));
} else {
buf[0] = partition_id;
buf[1] = tablet_id;
res_datum.set_string(reinterpret_cast<char *>(buf), buf_len);
}
return ret;
}
int ObExprCalcPartitionBase::extract_part_and_tablet_id(const ObDatum &part_datum,
ObObjectID &part_id,
ObTabletID &tablet_id)
{
int ret = OB_SUCCESS;
const ObString &part_str = part_datum.get_string();
if (part_str.length() < sizeof(uint64_t) * 2) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("the partition string need 16 byte at least", K(ret));
} else {
const uint64_t *id_array = reinterpret_cast<const uint64_t*>(part_str.ptr());
part_id = id_array[0];
tablet_id = id_array[1];
}
return ret;
}
int ObExprCalcPartitionBase::calc_part_and_tablet_id(const ObExpr *calc_part_id,
ObEvalCtx &eval_ctx,
ObObjectID &partition_id,
ObTabletID &tablet_id)
{
int ret = OB_SUCCESS;
ObDatum *partition_id_datum = NULL;
if (OB_ISNULL(calc_part_id) || !calc_part_id->datum_meta_.is_binary()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("calc part id is invalid", K(ret), KPC(calc_part_id));
} else if (OB_FAIL(calc_part_id->eval(eval_ctx, partition_id_datum))) {
LOG_WARN("calc part id expr failed", K(ret));
} else if (OB_FAIL(extract_part_and_tablet_id(*partition_id_datum, partition_id, tablet_id))) {
LOG_WARN("extract part and tablet id failed", K(ret));
} else if (ObExprCalcPartitionId::NONE_PARTITION_ID == partition_id) {
ret = OB_NO_PARTITION_FOR_GIVEN_VALUE;
LOG_DEBUG("no partition matched", K(ret), KPC(calc_part_id), KPC(partition_id_datum));
}
return ret;
}
int ObExprCalcPartitionBase::build_row(ObEvalCtx &ctx,
ObIAllocator &allocator,
const ObExpr &expr,
ObNewRow &row)
{
int ret = OB_SUCCESS;
OB_ASSERT(T_OP_ROW == expr.type_);
OB_ASSERT(expr.arg_cnt_ > 0);
if (OB_ISNULL(row.cells_ = static_cast<ObObj*>(allocator.alloc(sizeof(ObObj) * expr.arg_cnt_)))) {
//TODO shengle 这里后面可以将第一次分配的cells_内存放入expr_ctx,
// 重复使用进行优化;
if (OB_ISNULL(row.cells_ = static_cast<ObObj *>(
allocator.alloc(sizeof(ObObj) * expr.arg_cnt_)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("allocate memory failed", K(ret));
} else {
@ -224,9 +403,11 @@ int ObExprCalcPartitionId::build_row(ObEvalCtx& ctx, ObIAllocator& allocator, co
}
if (OB_SUCC(ret)) {
for (int64_t i = 0; OB_SUCC(ret) && i < expr.arg_cnt_; i++) {
ObExpr* col_expr = expr.args_[i];
ObDatum& col_datum = col_expr->locate_expr_datum(ctx);
if (OB_FAIL(col_datum.to_obj(row.cells_[i], col_expr->obj_meta_, col_expr->obj_datum_map_))) {
ObExpr *col_expr = expr.args_[i];
ObDatum &col_datum = col_expr->locate_expr_datum(ctx);
if (OB_FAIL(col_datum.to_obj(row.cells_[i],
col_expr->obj_meta_,
col_expr->obj_datum_map_))) {
LOG_WARN("convert datum to obj failed", K(ret));
}
}
@ -235,31 +416,77 @@ int ObExprCalcPartitionId::build_row(ObEvalCtx& ctx, ObIAllocator& allocator, co
return ret;
}
int ObExprCalcPartitionId::calc_partition_id(const ObExpr& part_expr, ObEvalCtx& ctx,
const CalcPartitionIdInfo& calc_part_info, int64_t first_part_id, ObDatum& res_datum)
int ObExprCalcPartitionBase::add_interval_part(ObExecContext &exec_ctx,
const CalcPartitionBaseInfo &calc_part_info,
ObIAllocator &allocator, ObNewRow &row)
{
int ret = OB_SUCCESS;
ObTaskExecutorCtx* tctx = GET_TASK_EXECUTOR_CTX(ctx.exec_ctx_);
ObSqlCtx* sql_ctx = ctx.exec_ctx_.get_sql_ctx();
int64_t res_part_id = NONE_PARTITION_ID;
ObSEArray<int64_t, 1> partition_ids;
ObPartitionLevel part_level = (NONE_PARTITION_ID == first_part_id) ? PARTITION_LEVEL_ONE : PARTITION_LEVEL_TWO;
ObPartitionFuncType part_type =
(PARTITION_LEVEL_ONE == part_level) ? calc_part_info.part_type_ : calc_part_info.subpart_type_;
if (OB_ISNULL(tctx) || OB_ISNULL(sql_ctx) || OB_ISNULL(sql_ctx->schema_guard_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(tctx), K(sql_ctx), K(ret));
} else if (is_virtual_table(calc_part_info.ref_table_id_) &&
OB_FAIL(tctx->init_calc_virtual_part_id_params(calc_part_info.ref_table_id_))) {
LOG_WARN("fail to init_calc_virtual_part_id_params", K(ret), K(calc_part_info));
// As long as init_calc_virtual_part_id_params is run, it must be run
// reset_calc_virtual_part_id_params
tctx->reset_calc_virtual_part_id_params();
if (MayAddIntervalPart::YES == calc_part_info.may_add_interval_part_) {
const uint64_t tenant_id = MTL_ID();
const ObTableSchema *table_schema = NULL;
bool is_interval = false;
CK (OB_NOT_NULL(exec_ctx.get_sql_ctx()));
OZ (exec_ctx.get_sql_ctx()->schema_guard_->get_table_schema(
tenant_id, calc_part_info.ref_table_id_, table_schema));
CK (OB_NOT_NULL(table_schema));
OX (is_interval = table_schema->is_interval_part());
if (OB_SUCC(ret) && is_interval) {
if (OB_FAIL(ObTableLocation::send_add_interval_partition_rpc_new_engine(
allocator, exec_ctx.get_sql_ctx()->session_info_,
exec_ctx.get_sql_ctx()->schema_guard_, table_schema, row))) {
if (is_need_retry_interval_part_error(ret)) {
set_interval_partition_insert_error(ret);
}
LOG_WARN("failed to send add interval partition rpc", K(ret));
} else {
set_interval_partition_insert_error(ret);
}
}
} else if (MayAddIntervalPart::PART_CHANGE_ERR == calc_part_info.may_add_interval_part_) {
ret = OB_ERR_UPD_CAUSE_PART_CHANGE;
LOG_WARN("cause partition movement", K(ret));
}
return ret;
}
/*
when the table is partitioned by interval, call this function may have three different action
when the partition id is not exist.
1. set part id to 0 indicate part not found, this is default action. used by normal part calc such
as join repart
2. add interval partition and set an error code force stmt retry. used by dml such as pdml shuffle
3. set and error code and make the query stop and report and error msg to client, used by update
partition key column which may cause partition changed. ex: update t1 set c1 = c1 + 201; t1 is
interval partitioned which only has one partition created (0-200), and partitioned by c1.
function add_interval_part handle case 2, 3. case 1 is default.
*
*/
int ObExprCalcPartitionBase::calc_partition_id(const ObExpr &part_expr,
ObEvalCtx &ctx,
const CalcPartitionBaseInfo &calc_part_info,
ObObjectID first_part_id,
ObTabletID &tablet_id,
ObObjectID &partition_id)
{
int ret = OB_SUCCESS;
ObSqlCtx *sql_ctx = ctx.exec_ctx_.get_sql_ctx();
tablet_id.reset();
partition_id = OB_INVALID_ID;
ObPartitionLevel part_level = (OB_INVALID_ID == first_part_id)
? PARTITION_LEVEL_ONE : PARTITION_LEVEL_TWO;
ObPartitionFuncType part_type = (PARTITION_LEVEL_ONE == part_level)
? calc_part_info.part_type_ : calc_part_info.subpart_type_;
ObDASTabletMapper tablet_mapper;
if (OB_FAIL(ctx.exec_ctx_.get_das_ctx().get_das_tablet_mapper(calc_part_info.ref_table_id_,
tablet_mapper,
&calc_part_info.related_table_ids_))) {
LOG_WARN("get das tablet mapper failed", K(ret), K(calc_part_info));
} else if (T_OP_ROW == part_expr.type_) {
ObDatum* tmp_datum = NULL;
// Calculate the value of expr child in advance, instead of calling eval directly in the build row,
// It is to avoid reset tmp alloc used in eval calculation, which affects the following allocation row
// cell memory usage of reset tmp alloc
ObDatum *tmp_datum = NULL;
//这里提前计算下expr child值, 而不是在build row中直接调用eval,
//是为了避免eval计算里面会使用reset tmp alloc, 影响下面分配row
//cell内存对reset tmp alloc的使用
for (int64_t i = 0; OB_SUCC(ret) && i < part_expr.arg_cnt_; i++) {
if (OB_FAIL(part_expr.args_[i]->eval(ctx, tmp_datum))) {
LOG_WARN("fail to eval part expr", K(ret), K(part_expr));
@ -267,192 +494,132 @@ int ObExprCalcPartitionId::calc_partition_id(const ObExpr& part_expr, ObEvalCtx&
}
if (OB_SUCC(ret)) {
ObNewRow row;
ObIAllocator& allocator = ctx.get_reset_tmp_alloc();
ObEvalCtx::TempAllocGuard alloc_guard(ctx);
ObIAllocator &allocator = alloc_guard.get_allocator();
if (OB_FAIL(build_row(ctx, allocator, part_expr, row))) {
LOG_WARN("fail to build row", K(ret));
} else if (OB_FAIL(sql_ctx->schema_guard_->get_part(
calc_part_info.ref_table_id_, part_level, first_part_id, row, partition_ids))) {
} else if (OB_FAIL(tablet_mapper.get_tablet_and_object_id(
part_level,
first_part_id,
row,
tablet_id,
partition_id))) {
LOG_WARN("Failed to get part id", K(ret), K(row));
} else if (partition_ids.count() != 0 && partition_ids.count() != 1) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid partition cnt", K(ret), K(partition_ids));
} else {
res_part_id = (0 == partition_ids.count()) ? NONE_PARTITION_ID : partition_ids.at(0);
if ((OB_INVALID_ID == partition_id) &&
PARTITION_LEVEL_ONE == part_level &&
NULL != ctx.exec_ctx_.get_my_session() &&
ORACLE_MODE == ctx.exec_ctx_.get_my_session()->get_compatibility_mode()) {
OZ (add_interval_part(ctx.exec_ctx_, calc_part_info, allocator, row),
calc_part_info, first_part_id);
}
}
}
} else { // not list/range columns
} else { // not list/range columns
ObObj func_value;
ObObj result;
ObDatum* datum = NULL;
ObDatum *datum = NULL;
if (OB_FAIL(part_expr.eval(ctx, datum))) {
LOG_WARN("part expr evaluate failed", K(ret));
} else if (OB_FAIL(datum->to_obj(func_value, part_expr.obj_meta_, part_expr.obj_datum_map_))) {
} else if (OB_FAIL(datum->to_obj(func_value,
part_expr.obj_meta_,
part_expr.obj_datum_map_))) {
LOG_WARN("convert datum to obj failed", K(ret));
} else if (!is_inner_table(calc_part_info.ref_table_id_)) {
} else {
result = func_value;
if (PARTITION_FUNC_TYPE_HASH == part_type || PARTITION_FUNC_TYPE_HASH_V2 == part_type) {
if (share::is_oracle_mode()) {
if (PARTITION_FUNC_TYPE_HASH == part_type) {
if (lib::is_oracle_mode()) {
// do nothing
} else if (PARTITION_FUNC_TYPE_HASH == part_type) {
if (OB_FAIL(ObExprFuncPartOldHash::calc_value_for_mysql(func_value, result))) {
LOG_WARN("Failed to calc hash value mysql mode", K(ret));
}
} else if (OB_FAIL(ObExprFuncPartHash::calc_value_for_mysql(func_value, result))) {
} else if (OB_FAIL(ObExprFuncPartHash::calc_value_for_mysql(func_value, result,
func_value.get_type()))) {
LOG_WARN("Failed to calc hash value mysql mode", K(ret));
}
}
if (OB_SUCC(ret)) {
ObSEArray<ObTabletID, 1> tablet_ids;
ObSEArray<ObObjectID, 1> partition_ids;
//这里也可以统一使用上面的ObNewRow接口, 并把calc_value_for_mysql
// 用datum实现下, 暂时和以前的方式保持一致
ObRowkey rowkey(const_cast<ObObj*>(&result), 1);
ObNewRange range;
if (OB_FAIL(range.build_range(calc_part_info.ref_table_id_, rowkey))) {
LOG_WARN("Failed to build range", K(ret));
} else if (OB_FAIL(sql_ctx->schema_guard_->get_part(
calc_part_info.ref_table_id_, part_level, first_part_id, range, false, partition_ids))) {
} else if (OB_FAIL(tablet_mapper.get_tablet_and_object_id(
part_level,
first_part_id,
range,
tablet_ids,
partition_ids))) {
LOG_WARN("Failed to get part id", K(ret));
} else if (partition_ids.count() != 0 && partition_ids.count() != 1) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid partition cnt", K(ret), K(partition_ids));
LOG_WARN("invalid partition cnt", K(ret), K(part_expr), K(partition_ids), K(range), K(rowkey));
} else {
res_part_id = (0 == partition_ids.count()) ? NONE_PARTITION_ID : partition_ids.at(0);
if (0 == partition_ids.count() &&
PARTITION_LEVEL_ONE == part_level &&
NULL != ctx.exec_ctx_.get_my_session() &&
ORACLE_MODE == ctx.exec_ctx_.get_my_session()->get_compatibility_mode()) {
ObEvalCtx::TempAllocGuard alloc_guard(ctx);
ObIAllocator &allocator = alloc_guard.get_allocator();
ObNewRow row(const_cast<ObObj*>(&result), 1);
OZ (add_interval_part(ctx.exec_ctx_, calc_part_info, allocator, row),
calc_part_info, first_part_id);
}
if (OB_SUCC(ret) && 1 == partition_ids.count()) {
partition_id = partition_ids.at(0);
if (1 == tablet_ids.count()) {
tablet_id = tablet_ids.at(0);
}
}
}
}
} else { // inner table
int64_t calc_result = 0;
if (OB_FAIL(func_value.get_int(calc_result))) {
LOG_WARN("Fail to get int64 from result", K(result), K(ret));
} else if (OB_INVALID_PARTITION_ID == calc_result && is_virtual_table(calc_part_info.ref_table_id_)) {
res_part_id = NONE_PARTITION_ID;
// addr is invalid, and partition id calculated by this addr is also invalid, so, do nothing
} else if (calc_result < 0 || 0 == calc_part_info.part_num_) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid arguments", K(calc_result), K(calc_part_info), K(ret));
} else {
res_part_id = calc_result % calc_part_info.part_num_;
}
}
}
if (OB_SUCC(ret)) {
res_datum.set_int(res_part_id);
int64_t part_idx = (NONE_PARTITION_ID == res_part_id) ? OB_INVALID_INDEX : 0;
ctx.exec_ctx_.get_part_row_manager().set_part_idx(part_idx);
if (is_virtual_table(calc_part_info.ref_table_id_)) {
tctx->reset_calc_virtual_part_id_params();
}
}
return ret;
}
int ObExprCalcPartitionId::get_opt_route(
const ObTableSchema& table_schema, const ObRawExpr& raw_expr, OptRouteType& opt_route_type)
//calc partition id
ObExprCalcPartitionId::ObExprCalcPartitionId(ObIAllocator &alloc)
: ObExprCalcPartitionBase(alloc,
T_FUN_SYS_CALC_PARTITION_ID,
N_CALC_PARTITION_ID,
PARAM_NUM_UNKNOWN,
NOT_ROW_DIMENSION)
{
int ret = OB_SUCCESS;
bool enable_opt = false;
if (OB_FAIL(enable_opt_route_hash_one(table_schema, raw_expr, enable_opt))) {
LOG_WARN("fail to check enable use opt route hash one", K(ret));
} else if (enable_opt) {
opt_route_type = OPT_ROUTE_HASH_ONE;
}
// If there are other optimized execution paths, add judgment after this
return ret;
}
// Determine the optimal path in different partition definition scenarios:
// 1.OPT_ROUTE_HASH_ONE optimization
// 1) Conditions:
// a. The access is not the internal table
// b. First-level partition
// c. hash partition (non-columns partition)
// d. All part_idx_ and part_id in ObPartition are the same, that is,
// no partition management related operations have been done,
// 2) Perform optimization:
// The number of hash partitions is stored in CalcPartitionIdInfo, no need to obtain schema,
// After calculating the partition part_idx according to the partition definition,
// there is no need to look up the mapping table of part_idx-->part_id, and return to part_idx directly
// 2. For other optimization scenarios,
// we will continue to sort out the part_idx-->part id mapping table in the expression for optimization calculations
int ObExprCalcPartitionId::enable_opt_route_hash_one(
const ObTableSchema& table_schema, const ObRawExpr& raw_expr, bool& enable_opt_route_hash_one)
ObExprCalcPartitionId::~ObExprCalcPartitionId()
{
int ret = OB_SUCCESS;
enable_opt_route_hash_one = true;
const ObRawExpr* part_expr = NULL;
if (is_inner_table(table_schema.get_table_id())) {
enable_opt_route_hash_one = false;
} else if (PARTITION_LEVEL_ONE != table_schema.get_part_level()) {
enable_opt_route_hash_one = false;
} else if (PARTITION_FUNC_TYPE_HASH != table_schema.get_part_option().get_part_func_type() &&
PARTITION_FUNC_TYPE_HASH_V2 != table_schema.get_part_option().get_part_func_type()) {
enable_opt_route_hash_one = false;
} else if (1 != raw_expr.get_param_count() || (NULL == (part_expr = raw_expr.get_param_expr(0)))) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", K(raw_expr), K(table_schema), K(ret));
} else if (T_OP_ROW == part_expr->get_expr_type()) {
enable_opt_route_hash_one = false;
} else {
ObPartition** part_array = table_schema.get_part_array();
bool same = true;
for (int64_t i = 0; same && OB_SUCC(ret) && i < table_schema.get_partition_num(); i++) {
if (OB_ISNULL(part_array[i])) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("get invalid partiton array", K(ret), K(i));
} else if (part_array[i]->get_part_idx() != part_array[i]->get_part_id()) {
same = false;
}
}
if (OB_SUCC(ret) && !same) {
enable_opt_route_hash_one = false;
}
}
return ret;
}
// 1.OPT_ROUTE_HASH_ONE optimization
// 1) Conditions:
// a. The access is not the internal table
// b. First-level partition
// c. hash partition (non-columns partition)
// d. All part_idx_ and part_id in ObPartition are the same, that is,
// no partition management related operations have been done,
// 2) Perform optimization:
// The number of hash partitions is stored in CalcPartitionIdInfo, no need to obtain schema,
// After calculating the partition part_idx according to the partition definition,
// there is no need to look up the mapping table of part_idx-->part_id, and return to part_idx directly
int ObExprCalcPartitionId::calc_opt_route_hash_one(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& res_datum)
//calc tablet id
ObExprCalcTabletId::ObExprCalcTabletId(ObIAllocator &alloc)
: ObExprCalcPartitionBase(alloc,
T_FUN_SYS_CALC_TABLET_ID,
N_CALC_TABLET_ID,
PARAM_NUM_UNKNOWN,
NOT_ROW_DIMENSION)
{
int ret = OB_SUCCESS;
OB_ASSERT(1 == expr.arg_cnt_);
OB_ASSERT(NULL != expr.args_[0]);
OB_ASSERT(expr.extra_ > 0);
CalcPartitionIdInfo* calc_part_info = reinterpret_cast<CalcPartitionIdInfo*>(expr.extra_);
ObDatum* datum = NULL;
int64_t part_idx = 0;
if (OB_FAIL(expr.args_[0]->eval(ctx, datum))) {
LOG_WARN("part expr evaluate failed", K(ret));
} else {
int64_t value = 0;
if (datum->is_null()) {
// do nothing
} else {
value = datum->get_int();
if (OB_UNLIKELY(INT64_MIN == value)) {
value = INT64_MAX;
} else {
value = value < 0 ? -value : value;
}
}
if (OB_FAIL(ObPartitionUtils::calc_hash_part_idx(value, calc_part_info->part_num_, part_idx))) {
LOG_WARN("fail to calc hash part idx", K(ret), K(*calc_part_info), K(datum->get_int()));
} else {
res_datum.set_int(part_idx);
LOG_TRACE("calc part id use opt route hash one", K(res_datum), K(*datum), K(*calc_part_info), K(value));
}
}
return ret;
}
} // namespace sql
} // namespace oceanbase
ObExprCalcTabletId::~ObExprCalcTabletId()
{
}
//calc partition id and tablet id
ObExprCalcPartitionTabletId::ObExprCalcPartitionTabletId(ObIAllocator &alloc)
: ObExprCalcPartitionBase(alloc,
T_FUN_SYS_CALC_PARTITION_TABLET_ID,
N_CALC_PARTITION_TABLET_ID,
PARAM_NUM_UNKNOWN,
NOT_ROW_DIMENSION)
{
}
ObExprCalcPartitionTabletId::~ObExprCalcPartitionTabletId()
{
}
}
}