From ea494d43817c25cb9319bdca30ddb9d97a52a5cc Mon Sep 17 00:00:00 2001 From: Josip Mrden Date: Fri, 5 May 2023 15:38:09 +0200 Subject: [PATCH] Merge from in list --- src/query/frontend/ast/ast.hpp | 5 ++++ src/query/interpret/eval.hpp | 42 ++++++++++++++++++++++++---------- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/query/frontend/ast/ast.hpp b/src/query/frontend/ast/ast.hpp index a1ecfafff..31caf7be8 100644 --- a/src/query/frontend/ast/ast.hpp +++ b/src/query/frontend/ast/ast.hpp @@ -666,11 +666,16 @@ class InListOperator : public memgraph::query::BinaryOperator { return object; } + void SetCachedSet(std::unordered_set &&set_) { _cached_set.emplace(set_); } + + std::unordered_set *GetCachedSet() { return _cached_set.has_value() ? &*_cached_set : nullptr; } + protected: using BinaryOperator::BinaryOperator; private: friend class AstStorage; + std::optional> _cached_set{std::nullopt}; }; class SubscriptOperator : public memgraph::query::BinaryOperator { diff --git a/src/query/interpret/eval.hpp b/src/query/interpret/eval.hpp index a094fcea0..0ff6afeb5 100644 --- a/src/query/interpret/eval.hpp +++ b/src/query/interpret/eval.hpp @@ -190,17 +190,27 @@ class ExpressionEvaluator : public ExpressionVisitor { } 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 { 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 _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);