Merge from in list

This commit is contained in:
Josip Mrden
2023-05-05 15:38:09 +02:00
parent 90d17f1bfd
commit ea494d4381
2 changed files with 35 additions and 12 deletions

View File

@@ -666,11 +666,16 @@ class InListOperator : public memgraph::query::BinaryOperator {
return object;
}
void SetCachedSet(std::unordered_set<size_t> &&set_) { _cached_set.emplace(set_); }
std::unordered_set<size_t> *GetCachedSet() { return _cached_set.has_value() ? &*_cached_set : nullptr; }
protected:
using BinaryOperator::BinaryOperator;
private:
friend class AstStorage;
std::optional<std::unordered_set<size_t>> _cached_set{std::nullopt};
};
class SubscriptOperator : public memgraph::query::BinaryOperator {

View File

@@ -190,17 +190,27 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
}
TypedValue Visit(InListOperator &in_list) override {
ReferenceExpressionEvaluator reference_expression_evaluator{frame_, symbol_table_, ctx_};
TypedValue *_list_ptr = in_list.expression2_->Accept(reference_expression_evaluator);
TypedValue _list;
if (nullptr == _list_ptr) {
_list = in_list.expression2_->Accept(*this);
_list_ptr = &_list;
}
auto literal = in_list.expression1_->Accept(*this);
auto _list = in_list.expression2_->Accept(*this);
if (_list.IsNull()) {
if (_list_ptr->IsNull()) {
return TypedValue(ctx_->memory);
}
// Exceptions have higher priority than returning nulls when list expression
// is not null.
if (_list.type() != TypedValue::Type::List) {
if (_list_ptr->type() != TypedValue::Type::List) {
throw QueryRuntimeException("IN expected a list, got {}.", _list.type());
}
const auto &list = _list.ValueList();
const auto &list = _list_ptr->ValueList();
// If literal is NULL there is no need to try to compare it with every
// element in the list since result of every comparison will be NULL. There
@@ -209,16 +219,24 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
if (list.empty()) return TypedValue(false, ctx_->memory);
if (literal.IsNull()) return TypedValue(ctx_->memory);
auto has_null = false;
for (const auto &element : list) {
auto result = literal == element;
if (result.IsNull()) {
has_null = true;
} else if (result.ValueBool()) {
return TypedValue(true, ctx_->memory);
if (in_list.GetCachedSet() == nullptr) {
std::unordered_set<size_t> _cached_set;
TypedValue::Hash hash{};
for (const TypedValue &element : list) {
_cached_set.insert(hash(element));
}
in_list.SetCachedSet(std::move(_cached_set));
}
if (has_null) {
const auto &in_list_cached_set = in_list.GetCachedSet();
TypedValue::Hash hash{};
if (in_list_cached_set->contains(hash(literal))) {
return TypedValue(true, ctx_->memory);
}
// has null
if (literal.type() == TypedValue::Type::Null || in_list_cached_set->contains(hash(TypedValue(ctx_->memory)))) {
return TypedValue(ctx_->memory);
}
return TypedValue(false, ctx_->memory);