[Doris On ES] [Bug-Fix][Refactor] Fix potential null pointer exception and refactor function process logic (#3985)

fix: https://github.com/apache/incubator-doris/issues/3984

1. add `conjunct.size` checking and `slot_desc nullptr` checking logic
2. For historical reasons, the function predicates are added one by one, I just refactor the processing make thelogic for function predicate processing more clearly
This commit is contained in:
Yunfeng,Wu
2020-07-02 22:32:16 +08:00
committed by GitHub
parent 5ade21b55d
commit 1e813df3fd
2 changed files with 86 additions and 94 deletions

View File

@ -226,11 +226,11 @@ static bool is_literal_node(const Expr* expr) {
}
Status EsPredicate::build_disjuncts_list(const Expr* conjunct) {
// process binary predicate
if (TExprNodeType::BINARY_PRED == conjunct->node_type()) {
if (conjunct->children().size() != 2) {
return Status::InternalError("build disjuncts failed: number of childs is not 2");
}
SlotRef* slot_ref = nullptr;
TExprOpcode::type op;
Expr* expr = nullptr;
@ -243,7 +243,7 @@ Status EsPredicate::build_disjuncts_list(const Expr* conjunct) {
if (TExprNodeType::SLOT_REF == conjunct->get_child(0)->node_type()
|| TExprNodeType::CAST_EXPR == conjunct->get_child(0)->node_type()) {
expr = conjunct->get_child(1);
// process such as sub-query: select * from (select split_part(k, "_", 1) as new_field from case_replay_for_milimin) t where t.new_field > 1;
// process such as sub-query: select * from (select split_part(k, "_", 1) as new_field from table) t where t.new_field > 1;
RETURN_ERROR_IF_EXPR_IS_NOT_SLOTREF(conjunct->get_child(0));
// process cast expr, such as:
// k (float) > 2.0, k(int) > 3.2
@ -283,93 +283,94 @@ Status EsPredicate::build_disjuncts_list(const Expr* conjunct) {
_disjuncts.push_back(predicate);
return Status::OK();
}
if (is_match_func(conjunct)) {
Expr* expr = conjunct->get_child(1);
ExtLiteral literal(expr->type().type, _context->get_value(expr, NULL));
vector<ExtLiteral> query_conditions;
query_conditions.emplace_back(literal);
vector<ExtColumnDesc> cols; //TODO
ExtPredicate* predicate = new ExtFunction(
TExprNodeType::FUNCTION_CALL,
conjunct->fn().name.function_name,
cols,
query_conditions);
if (_es_query_status.ok()) {
_es_query_status
= BooleanQueryBuilder::check_es_query(*(ExtFunction *)predicate);
if (!_es_query_status.ok()) {
delete predicate;
return _es_query_status;
}
}
_disjuncts.push_back(predicate);
return Status::OK();
}
if (TExprNodeType::FUNCTION_CALL == conjunct->node_type()
&& (conjunct->fn().name.function_name == "is_null_pred" || conjunct->fn().name.function_name == "is_not_null_pred")) {
// such as sub-query: select * from (select split_part(k, "_", 1) as new_field from case_replay_for_milimin) t where t.new_field > 1;
// conjunct->get_child(0)->node_type() == TExprNodeType::FUNCTION_CALL, at present doris on es can not support push down function
RETURN_ERROR_IF_EXPR_IS_NOT_SLOTREF(conjunct->get_child(0));
SlotRef* slot_ref = (SlotRef*)(conjunct->get_child(0));
const SlotDescriptor* slot_desc = get_slot_desc(slot_ref);
bool is_not_null;
if (conjunct->fn().name.function_name == "is_null_pred") {
is_not_null = false;
} else {
is_not_null = true;
}
std::string col = slot_desc->col_name();
if (_field_context.find(col) != _field_context.end()) {
col = _field_context[col];
}
// use TExprNodeType::IS_NULL_PRED for BooleanQueryBuilder translate
ExtIsNullPredicate* predicate = new ExtIsNullPredicate(TExprNodeType::IS_NULL_PRED, col, slot_desc->type(), is_not_null);
_disjuncts.push_back(predicate);
return Status::OK();
}
// process function call predicate: esquery, is_null_pred, is_not_null_pred
if (TExprNodeType::FUNCTION_CALL == conjunct->node_type()) {
std::string fname = conjunct->fn().name.function_name;
if (fname != "like") {
return Status::InternalError("build disjuncts failed: function name is not like");
}
if (fname == "esquery") {
if (conjunct->children().size() != 2) {
return Status::InternalError("build disjuncts failed: number of childs is not 2");
}
Expr* expr = conjunct->get_child(1);
ExtLiteral literal(expr->type().type, _context->get_value(expr, NULL));
vector<ExtLiteral> query_conditions;
query_conditions.emplace_back(literal);
vector<ExtColumnDesc> cols;
ExtPredicate* predicate = new ExtFunction(
TExprNodeType::FUNCTION_CALL,
"esquery",
cols,
query_conditions);
if (_es_query_status.ok()) {
_es_query_status = BooleanQueryBuilder::check_es_query(*(ExtFunction *)predicate);
if (!_es_query_status.ok()) {
delete predicate;
return _es_query_status;
}
}
_disjuncts.push_back(predicate);
} else if (fname == "is_null_pred" || fname == "is_not_null_pred") {
if (conjunct->children().size() != 1) {
return Status::InternalError("build disjuncts failed: number of childs is not 1");
}
// such as sub-query: select * from (select split_part(k, "_", 1) as new_field from table) t where t.new_field > 1;
// conjunct->get_child(0)->node_type() == TExprNodeType::FUNCTION_CALL, at present doris on es can not support push down function
RETURN_ERROR_IF_EXPR_IS_NOT_SLOTREF(conjunct->get_child(0));
SlotRef* slot_ref = (SlotRef*)(conjunct->get_child(0));
const SlotDescriptor* slot_desc = get_slot_desc(slot_ref);
if (slot_desc == nullptr) {
return Status::InternalError("build disjuncts failed: no SLOT_REF child");
}
bool is_not_null = fname == "is_not_null_pred" ? true : false;
std::string col = slot_desc->col_name();
if (_field_context.find(col) != _field_context.end()) {
col = _field_context[col];
}
// use TExprNodeType::IS_NULL_PRED for BooleanQueryBuilder translate
ExtIsNullPredicate* predicate = new ExtIsNullPredicate(TExprNodeType::IS_NULL_PRED, col, slot_desc->type(), is_not_null);
_disjuncts.push_back(predicate);
} else if (fname == "like") {
if (conjunct->children().size() != 2) {
return Status::InternalError("build disjuncts failed: number of childs is not 2");
}
SlotRef* slot_ref = nullptr;
Expr* expr = nullptr;
if (TExprNodeType::SLOT_REF == conjunct->get_child(0)->node_type()) {
expr = conjunct->get_child(1);
slot_ref = (SlotRef*)(conjunct->get_child(0));
} else if (TExprNodeType::SLOT_REF == conjunct->get_child(1)->node_type()) {
expr = conjunct->get_child(0);
slot_ref = (SlotRef*)(conjunct->get_child(1));
} else {
return Status::InternalError("build disjuncts failed: no SLOT_REF child");
}
const SlotDescriptor* slot_desc = get_slot_desc(slot_ref);
if (slot_desc == nullptr) {
return Status::InternalError("build disjuncts failed: slot_desc is null");
}
SlotRef* slot_ref = nullptr;
Expr* expr = nullptr;
if (TExprNodeType::SLOT_REF == conjunct->get_child(0)->node_type()) {
expr = conjunct->get_child(1);
slot_ref = (SlotRef*)(conjunct->get_child(0));
} else if (TExprNodeType::SLOT_REF == conjunct->get_child(1)->node_type()) {
expr = conjunct->get_child(0);
slot_ref = (SlotRef*)(conjunct->get_child(1));
PrimitiveType type = expr->type().type;
if (type != TYPE_VARCHAR && type != TYPE_CHAR) {
return Status::InternalError("build disjuncts failed: like value is not a string");
}
std::string col = slot_desc->col_name();
if (_field_context.find(col) != _field_context.end()) {
col = _field_context[col];
}
ExtLiteral literal(type, _context->get_value(expr, NULL));
ExtPredicate* predicate = new ExtLikePredicate(
TExprNodeType::LIKE_PRED,
col,
slot_desc->type(),
literal);
_disjuncts.push_back(predicate);
} else {
return Status::InternalError("build disjuncts failed: no SLOT_REF child");
std::stringstream ss;
ss << "can not process function predicate[ "
<< fname
<< " ]";
return Status::InternalError(ss.str());
}
const SlotDescriptor* slot_desc = get_slot_desc(slot_ref);
if (slot_desc == nullptr) {
return Status::InternalError("build disjuncts failed: slot_desc is null");
}
PrimitiveType type = expr->type().type;
if (type != TYPE_VARCHAR && type != TYPE_CHAR) {
return Status::InternalError("build disjuncts failed: like value is not a string");
}
std::string col = slot_desc->col_name();
if (_field_context.find(col) != _field_context.end()) {
col = _field_context[col];
}
ExtLiteral literal(type, _context->get_value(expr, NULL));
ExtPredicate* predicate = new ExtLikePredicate(
TExprNodeType::LIKE_PRED,
col,
slot_desc->type(),
literal);
_disjuncts.push_back(predicate);
return Status::OK();
}
@ -465,14 +466,6 @@ Status EsPredicate::build_disjuncts_list(const Expr* conjunct) {
return Status::InternalError(ss.str());
}
bool EsPredicate::is_match_func(const Expr* conjunct) {
if (TExprNodeType::FUNCTION_CALL == conjunct->node_type()
&& conjunct->fn().name.function_name == "esquery") {
return true;
}
return false;
}
const SlotDescriptor* EsPredicate::get_slot_desc(const SlotRef* slotRef) {
const SlotDescriptor* slot_desc = nullptr;
for (SlotDescriptor* slot : _tuple_desc->slots()) {

View File

@ -179,7 +179,7 @@ struct ExtFunction : public ExtPredicate {
values(values) {
}
const std::string& func_name;
const std::string func_name;
std::vector<ExtColumnDesc> cols;
const std::vector<ExtLiteral> values;
};
@ -205,7 +205,6 @@ public:
private:
Status build_disjuncts_list(const Expr* conjunct);
bool is_match_func(const Expr* conjunct);
const SlotDescriptor* get_slot_desc(const SlotRef* slotRef);
ExprContext* _context;