polardbxengine/plugin/polarx_rpc/executor/expr.cc

514 lines
16 KiB
C++

#include <string>
#include <unordered_map>
#include "../global_defines.h"
#ifdef MYSQL8
# include "sql/current_thd.h"
#else
#define MYSQL_SERVER
#endif
#include "sql/sql_class.h"
#include "sql/my_decimal.h"
#include "sql/item_func.h"
#include "sql/item_cmpfunc.h"
#include "expr.h"
#include "parse.h"
#include "bloomfilter.h"
#include "log.h"
namespace rpc_executor {
template <class ITEM>
class Op1Factory {
public:
static ITEM *create(ExprItem *param) {
ITEM *item_op = new ITEM(param);
#ifdef MYSQL8
item_op->resolve_type(current_thd);
#else
item_op->fix_length_and_dec();
item_op->update_used_tables();
#endif
item_op->fixed = 1;
return item_op;
}
};
template <class ITEM>
class Op2Factory {
public:
static ITEM *create(ExprItem *lhs, ExprItem *rhs) {
ITEM *item_op = new ITEM(lhs, rhs);
#ifdef MYSQL8
item_op->resolve_type(current_thd);
#else
item_op->fix_length_and_dec();
item_op->update_used_tables();
#endif
item_op->fixed = 1;
return item_op;
}
};
template <>
class Op2Factory<Item_func_div> {
public:
static Item_func_div *create(ExprItem *lhs, ExprItem *rhs) {
POS pos;
Item_func_div *item_op = new Item_func_div(pos, lhs, rhs);
#ifdef MYSQL8
item_op->resolve_type(current_thd);
#else
item_op->fix_length_and_dec();
item_op->update_used_tables();
#endif
item_op->fixed = 1;
return item_op;
}
};
template <>
class Op2Factory<Item_func_isnull> {
public:
static Item_func_isnull *create(ExprItem *lhs, ExprItem *rhs) {
if (rhs->type() != ExprItem::NULL_ITEM) {
log_exec_error("operator is_null takes a not null value as 2nd param");
return nullptr;
}
Item_func_isnull *item_op = new Item_func_isnull(lhs);
#ifdef MYSQL8
item_op->resolve_type(current_thd);
#else
item_op->fix_length_and_dec();
item_op->update_used_tables();
#endif
item_op->fixed = 1;
return item_op;
}
};
template <>
class Op2Factory<Item_func_isnotnull> {
public:
static Item_func_isnotnull *create(ExprItem *lhs, ExprItem *rhs) {
if (rhs->type() != ExprItem::NULL_ITEM) {
log_exec_error("operator not_null takes a not null value as 2nd param");
return nullptr;
}
Item_func_isnotnull *item_op = new Item_func_isnotnull(lhs);
#ifdef MYSQL8
item_op->resolve_type(current_thd);
#else
item_op->fix_length_and_dec();
item_op->update_used_tables();
#endif
item_op->fixed = 1;
return item_op;
}
};
ExprParser &ExprParser::instance() {
static ExprParser parser;
return parser;
}
int ExprParser::parse(const ::Polarx::Expr::Expr &arg,
InternalDataSet &dataset,
ExprItem *&item) const {
int ret = HA_EXEC_SUCCESS;
THD *thd = current_thd;
switch (arg.type()) {
case ::Polarx::Expr::Expr::IDENT:
ret = parse(arg.identifier(), dataset, item);
break;
case ::Polarx::Expr::Expr::LITERAL:
ret = parse(arg.literal(), dataset, item);
break;
case ::Polarx::Expr::Expr::VARIABLE:
ret = HA_ERR_UNSUPPORTED;
log_exec_error("::Polarx::Expr::Expr::VARIABLE is not supported yet");
break;
case ::Polarx::Expr::Expr::FUNC_CALL:
ret = parse(arg.function_call(), dataset, item);
break;
case ::Polarx::Expr::Expr::OPERATOR:
ret = parse(arg.operator_(), dataset, item);
break;
case ::Polarx::Expr::Expr::PLACEHOLDER:
ret = parse_placeholder(arg.position(), dataset, item);
break;
case ::Polarx::Expr::Expr::OBJECT:
ret = parse(arg.object(), dataset, item);
break;
case ::Polarx::Expr::Expr::ARRAY:
ret = parse(arg.array(), dataset, item);
break;
case ::Polarx::Expr::Expr::REF:
ret = parse_fieldref(arg.ref_id(), dataset, item);
break;
default:
ret = HA_ERR_UNSUPPORTED;
log_exec_error("Invalid value for type: %d", arg.type());
break;
}
if (thd && thd->is_error()) {
ret = thd->get_stmt_da()->mysql_errno();
}
return ret;
}
int ExprParser::parse(const ::Polarx::Expr::Operator &op,
InternalDataSet &dataset,
ExprItem *&item) const {
int ret = HA_EXEC_SUCCESS;
static std::unordered_map<std::string, std::function<ExprItem*(ExprItem*,ExprItem*)>> op2_map = {
{"+", Op2Factory<Item_func_plus>::create},
{"-", Op2Factory<Item_func_minus>::create},
{"*", Op2Factory<Item_func_mul>::create},
{"/", Op2Factory<Item_func_div>::create},
{"div", Op2Factory<Item_func_int_div>::create},
{"%", Op2Factory<Item_func_mod>::create},
{">", Op2Factory<Item_func_gt>::create},
{">=", Op2Factory<Item_func_ge>::create},
{"<", Op2Factory<Item_func_lt>::create},
{"<=", Op2Factory<Item_func_le>::create},
{"==", Op2Factory<Item_func_eq>::create},
{"<=>", Op2Factory<Item_func_equal>::create},
{"!=", Op2Factory<Item_func_ne>::create},
{"&&", Op2Factory<Item_cond_and>::create},
{"||", Op2Factory<Item_cond_or>::create},
{"is", Op2Factory<Item_func_isnull>::create},
{"is_not", Op2Factory<Item_func_isnotnull>::create}
};
static std::unordered_map<std::string, std::function<ExprItem*(ExprItem*)>> op1_map = {
{"!", Op1Factory<Item_func_not>::create}
};
if (op.param_size() == 2) {
const auto &iter = op2_map.find(op.name());
if (op2_map.end() == iter) {
ret = HA_ERR_UNSUPPORTED;
log_exec_error("Expr parse, operator type not support %s",
op.name().data());
} else {
ExprItem *lhs = nullptr;
ExprItem *rhs = nullptr;
if ((ret = parse(op.param(0), dataset, lhs))) {
log_exec_error("Expr parse left op of 2op failed, "
"ret: %d", ret);
} else if ((ret = parse(op.param(1), dataset, rhs))) {
log_exec_error("Expr parse right op of 2op failed, "
"ret: %d", ret);
} else {
auto *item_op = (iter->second)(lhs, rhs);
if (!item_op) {
ret = HA_ERR_OUT_OF_MEM;
} else {
dataset.defer_delete_item(item_op);
item = item_op;
}
}
}
} else if (op.param_size() == 1) {
const auto &iter = op1_map.find(op.name());
if (op1_map.end() == iter) {
ret = HA_ERR_UNSUPPORTED;
log_exec_error("Expr parse, operator type not support %s",
op.name().data());
} else {
ExprItem *param = nullptr;
if ((ret = parse(op.param(0), dataset, param))) {
log_exec_error("Expr parse op of 1op failed, "
"ret: %d", ret);
} else {
auto *item_op = (iter->second)(param);
if (!item_op) {
ret = HA_ERR_OUT_OF_MEM;
} else {
dataset.defer_delete_item(item_op);
item = item_op;
}
}
}
} else if (op.param_size() > 2) {
if (op.name() == "&&" || op.name() == "||") {
const auto &iter = op2_map.find(op.name());
assert(op2_map.end() != iter);
ExprItem *last_item = nullptr;
int last_param_idx = op.param_size() - 1;
if ((ret = parse(op.param(last_param_idx), dataset, last_item))) {
log_exec_error("Expr parse last(%d) param failed, "
"ret: %d", last_param_idx, ret);
} else {
for (int param_idx = last_param_idx - 1; param_idx >= 0; --param_idx) {
ExprItem *another_item = nullptr;
if ((ret = parse(op.param(param_idx), dataset, another_item))) {
log_exec_error("Expr parse %d param failed, "
"ret: %d", param_idx, ret);
} else {
last_item = (iter->second)(another_item, last_item);
if (!last_item) {
log_exec_error("Expr parse generate op item failed, "
"param_idx: %d, ret: %d", param_idx, ret);
ret = HA_ERR_OUT_OF_MEM;
break;
} else {
dataset.defer_delete_item(last_item);
}
}
}
if (HA_EXEC_SUCCESS == ret) {
item = last_item;
}
}
} else {
ret = HA_ERR_UNSUPPORTED;
log_exec_error("Expr parse, operator count not support %s, %d",
op.name().data(), op.param_size());
}
}
return ret;
}
int ExprParser::parse(const ::Polarx::Datatypes::Scalar &literal,
InternalDataSet &dataset,
ExprItem *&item) const {
int ret = HA_EXEC_SUCCESS;
::Polarx::Datatypes::Scalar_Type type = literal.type();
my_decimal decimal_value;
switch (type) {
case MysqlxScalar::V_SINT:
item = new ::Item_int(static_cast<longlong>(literal.v_signed_int()));
dataset.defer_delete_item(item);
break;
case MysqlxScalar::V_UINT:
item = new ::Item_int(static_cast<ulonglong>(literal.v_unsigned_int()));
dataset.defer_delete_item(item);
break;
case MysqlxScalar::V_NULL:
item = new ::Item_null();
dataset.defer_delete_item(item);
break;
case MysqlxScalar::V_OCTETS:
ret = parse(literal.v_octets(), dataset, item);
break;
case MysqlxScalar::V_DOUBLE:
double2my_decimal(E_DEC_FATAL_ERROR, literal.v_double(), &decimal_value);
item = new ::Item_float(literal.v_double(), decimal_value.frac);
dataset.defer_delete_item(item);
break;
case MysqlxScalar::V_FLOAT:
double2my_decimal(E_DEC_FATAL_ERROR, literal.v_float(), &decimal_value);
item = new ::Item_float(literal.v_float(), decimal_value.frac);
dataset.defer_delete_item(item);
break;
case MysqlxScalar::V_BOOL:
item = new ::Item_int(literal.v_bool() ? 1 : 0);
dataset.defer_delete_item(item);
break;
case MysqlxScalar::V_STRING:
item = new ::Item_string(literal.v_string().value().data(),
literal.v_string().value().size(),
&my_charset_utf8mb4_bin);
dataset.defer_delete_item(item);
break;
case MysqlxScalar::V_PLACEHOLDER:
ret = parse(real(literal), dataset, item);
break;
default:
ret = HA_ERR_UNSUPPORTED;
}
if (!ret) {
if (!item) {
ret = HA_ERR_OUT_OF_MEM;
}
}
return ret;
}
int ExprParser::parse(const ::Polarx::Expr::Identifier &arg,
InternalDataSet &dataset,
ExprItem *&item,
const bool is_function) const {
int ret = HA_EXEC_SUCCESS;
abort();
return ret;
}
int ExprParser::parse(const ::Polarx::Expr::ColumnIdentifier &arg,
InternalDataSet &dataset,
ExprItem *&item) const {
int ret = HA_EXEC_SUCCESS;
abort();
return ret;
}
int ExprParser::parse(const ::Polarx::Expr::FunctionCall &func,
InternalDataSet &dataset,
ExprItem *&item) const {
int ret = HA_EXEC_SUCCESS;
const std::string &func_name = func.name().name();
if (func_name != "bloomfilter") {
log_exec_error("unknown function name: %s", func_name.data());
ret = HA_ERR_UNSUPPORTED;
return ret;
}
std::vector<ExprItem*> params(func.param_size(), nullptr);
for (int32_t i = 0; i < func.param_size(); ++i) {
if ((ret = parse(func.param(i), dataset, params[i]))) {
log_exec_error("ExprParser parse FunctionCall.param failed, "
"ret: %d, idx: %d", ret, i);
break;
}
}
if (!ret) {
BloomFilterItem *bloomfilter_item = new BloomFilterItem();
if (!bloomfilter_item) {
ret = HA_ERR_OUT_OF_MEM;
log_exec_error("BloomFilterItem new error, out of memory");
} else if ((ret = bloomfilter_item->init(params))) {
delete bloomfilter_item;
bloomfilter_item = nullptr;
log_exec_error("BloomFilterItem init error, ret: %d", ret);
} else {
dataset.defer_delete_item(bloomfilter_item);
#ifdef MYSQL8
bloomfilter_item->resolve_type(current_thd);
#endif
bloomfilter_item->item_name.copy("bloom");
bloomfilter_item->fixed = 1;
item = bloomfilter_item;
}
}
return ret;
}
int ExprParser::parse(const ::Polarx::Datatypes::Any &arg,
InternalDataSet &dataset,
ExprItem *&item) const {
int ret = HA_EXEC_SUCCESS;
abort();
return ret;
}
int ExprParser::parse(const ::Polarx::Datatypes::Scalar::Octets &octets,
InternalDataSet &dataset,
ExprItem *&item) const {
int ret = HA_EXEC_SUCCESS;
item = new ::Item_string(octets.value().data(),
octets.value().size(),
&my_charset_bin);
dataset.defer_delete_item(item);
return ret;
}
int ExprParser::parse_placeholder(const Placeholder &arg_pos,
InternalDataSet &dataset,
ExprItem *&item) const {
return parse(tls_params->Get(arg_pos), dataset, item);
}
int ExprParser::parse(const ::Polarx::Expr::Object &arg,
InternalDataSet &dataset,
ExprItem *&item) const {
int ret = HA_EXEC_SUCCESS;
abort();
return ret;
}
int ExprParser::parse(const ::Polarx::Expr::Object::ObjectField &arg,
InternalDataSet &dataset,
ExprItem *&item) const {
int ret = HA_EXEC_SUCCESS;
abort();
return ret;
}
int ExprParser::parse(const ::Polarx::Expr::Array &arg,
InternalDataSet &dataset,
ExprItem *&item) const {
int ret = HA_EXEC_SUCCESS;
abort();
return ret;
}
int ExprParser::parse_fieldref(const FieldIndex &index,
InternalDataSet &dataset,
ExprItem *&item) const {
int ret = HA_EXEC_SUCCESS;
if (dataset.has_project()) {
ProjectInfo &items = dataset.get_project_exprs();
if (index >= items.size()) {
ret = HA_ERR_TOO_MANY_FIELDS;
log_exec_error("Expr parse REF, "
"field index > project expr size %u >= %lu",
index, items.size());
} else {
item = items[index].second;
}
} else {
Field **fields = nullptr;
uint32_t field_count = 0;
dataset.get_all_fields(fields, field_count);
if (index >= field_count) {
ret = HA_ERR_TOO_MANY_FIELDS;
log_exec_error("Expr parse REF, field index > total field %u >= %u",
index, field_count);
} else if (!(item = new Item_field(fields[index]))) {
ret = HA_ERR_OUT_OF_MEM;
log_exec_error("Expr new Item_field failed");
} else {
dataset.defer_delete_item(item);
dataset.project_field(fields[index]);
}
}
return ret;
}
int ExprParser::parse_field(const ::Polarx::Datatypes::Scalar &field_mark,
InternalDataSet &dataset,
ExprItem *&item,
const char *&field_name) const {
int ret = HA_EXEC_SUCCESS;
const ::Polarx::Datatypes::Scalar &real_field = real(field_mark);
Field *field = nullptr;
if (real_field.type() == ::Polarx::Datatypes::Scalar::V_UINT) {
uint64_t field_index = real_field.v_unsigned_int();
if ((ret = dataset.get_field(field_index, field))) {
log_exec_error("ExprParse can not parse field, "
"field_index: %lu, ret: %d",
field_index, ret);
}
} else {
const std::string &target_field_name = real_field.v_string().value();
if ((ret = dataset.get_field(&target_field_name, field))) {
log_exec_error("ExprParse can not parse field, "
"field_name: %s, ret: %d",
target_field_name.data(), ret);
}
}
if (ret) {
} else if (!(item = new Item_field(field))) {
ret = HA_ERR_OUT_OF_MEM;
log_exec_error("Expr new Item_field failed, no memory");
} else {
field_name = field->field_name;
dataset.defer_delete_item(item);
dataset.project_field(field);
}
return ret;
}
} // namespace executor