Fix PROFILE infinite loop (#1431)
This commit is contained in:
parent
011caf3bf1
commit
b1c3168308
@ -2456,17 +2456,16 @@ Filter::FilterCursor::FilterCursor(const Filter &self, utils::MemoryResource *me
|
||||
bool Filter::FilterCursor::Pull(Frame &frame, ExecutionContext &context) {
|
||||
OOMExceptionEnabler oom_exception;
|
||||
SCOPED_PROFILE_OP_BY_REF(self_);
|
||||
|
||||
|
||||
// Like all filters, newly set values should not affect filtering of old
|
||||
// nodes and edges.
|
||||
ExpressionEvaluator evaluator(&frame, context.symbol_table, context.evaluation_context, context.db_accessor,
|
||||
storage::View::OLD, context.frame_change_collector);
|
||||
while (input_cursor_->Pull(frame, context) || UNLIKELY(context.is_profile_query)) {
|
||||
while (input_cursor_->Pull(frame, context)) {
|
||||
for (const auto &pattern_filter_cursor : pattern_filter_cursors_) {
|
||||
pattern_filter_cursor->Pull(frame, context);
|
||||
}
|
||||
if (EvaluateFilter(evaluator, self_.expression_)) return true;
|
||||
if (UNLIKELY(context.is_profile_query)) return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -2790,13 +2789,15 @@ SetProperties::SetPropertiesCursor::SetPropertiesCursor(const SetProperties &sel
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
concept AccessorWithProperties = requires(T value, storage::PropertyId property_id,
|
||||
storage::PropertyValue property_value,
|
||||
std::map<storage::PropertyId, storage::PropertyValue> properties) {
|
||||
{ value.ClearProperties() } -> std::same_as<storage::Result<std::map<storage::PropertyId, storage::PropertyValue>>>;
|
||||
{value.SetProperty(property_id, property_value)};
|
||||
{value.UpdateProperties(properties)};
|
||||
};
|
||||
concept AccessorWithProperties =
|
||||
requires(T value, storage::PropertyId property_id, storage::PropertyValue property_value,
|
||||
std::map<storage::PropertyId, storage::PropertyValue> properties) {
|
||||
{
|
||||
value.ClearProperties()
|
||||
} -> std::same_as<storage::Result<std::map<storage::PropertyId, storage::PropertyValue>>>;
|
||||
{ value.SetProperty(property_id, property_value) };
|
||||
{ value.UpdateProperties(properties) };
|
||||
};
|
||||
|
||||
/// Helper function that sets the given values on either a Vertex or an Edge.
|
||||
///
|
||||
|
@ -69,6 +69,7 @@ add_subdirectory(transaction_rollback)
|
||||
add_subdirectory(index_hints)
|
||||
add_subdirectory(query_modules)
|
||||
add_subdirectory(constraints)
|
||||
add_subdirectory(inspect_query)
|
||||
|
||||
copy_e2e_python_files(pytest_runner pytest_runner.sh "")
|
||||
copy_e2e_python_files(x x.sh "")
|
||||
|
6
tests/e2e/inspect_query/CMakeLists.txt
Normal file
6
tests/e2e/inspect_query/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
function(copy_inspect_query_e2e_python_files FILE_NAME)
|
||||
copy_e2e_python_files(inspect_query ${FILE_NAME})
|
||||
endfunction()
|
||||
|
||||
copy_inspect_query_e2e_python_files(common.py)
|
||||
copy_inspect_query_e2e_python_files(inspect_query.py)
|
45
tests/e2e/inspect_query/common.py
Normal file
45
tests/e2e/inspect_query/common.py
Normal file
@ -0,0 +1,45 @@
|
||||
# Copyright 2023 Memgraph Ltd.
|
||||
#
|
||||
# Use of this software is governed by the Business Source License
|
||||
# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
# License, and you may not use this file except in compliance with the Business Source License.
|
||||
#
|
||||
# As of the Change Date specified in that file, in accordance with
|
||||
# the Business Source License, use of this software will be governed
|
||||
# by the Apache License, Version 2.0, included in the file
|
||||
# licenses/APL.txt.
|
||||
|
||||
import typing
|
||||
|
||||
import mgclient
|
||||
import pytest
|
||||
from gqlalchemy import Memgraph
|
||||
|
||||
|
||||
def execute_and_fetch_all(cursor: mgclient.Cursor, query: str, params: dict = {}) -> typing.List[tuple]:
|
||||
cursor.execute(query, params)
|
||||
return cursor.fetchall()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def connect(**kwargs) -> mgclient.Connection:
|
||||
connection = mgclient.connect(host="localhost", port=7687, **kwargs)
|
||||
connection.autocommit = True
|
||||
cursor = connection.cursor()
|
||||
execute_and_fetch_all(cursor, "USE DATABASE memgraph")
|
||||
try:
|
||||
execute_and_fetch_all(cursor, "DROP DATABASE clean")
|
||||
except:
|
||||
pass
|
||||
execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n")
|
||||
yield connection
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def memgraph(**kwargs) -> Memgraph:
|
||||
memgraph = Memgraph()
|
||||
|
||||
yield memgraph
|
||||
|
||||
memgraph.drop_database()
|
||||
memgraph.drop_indexes()
|
47
tests/e2e/inspect_query/inspect_query.py
Normal file
47
tests/e2e/inspect_query/inspect_query.py
Normal file
@ -0,0 +1,47 @@
|
||||
# Copyright 2023 Memgraph Ltd.
|
||||
#
|
||||
# Use of this software is governed by the Business Source License
|
||||
# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||
# License, and you may not use this file except in compliance with the Business Source License.
|
||||
#
|
||||
# As of the Change Date specified in that file, in accordance with
|
||||
# the Business Source License, use of this software will be governed
|
||||
# by the Apache License, Version 2.0, included in the file
|
||||
# licenses/APL.txt.
|
||||
|
||||
import sys
|
||||
|
||||
import mgclient
|
||||
import pytest
|
||||
from common import memgraph
|
||||
|
||||
|
||||
def test_label_index_hint(memgraph):
|
||||
explain_query = "EXPLAIN MATCH (n:Node) RETURN n.property1;"
|
||||
profile_query = "PROFILE MATCH (n:Node) RETURN n.property1;"
|
||||
|
||||
expected_profile = ["* Produce {n.property1}", "* Filter (n :Node)", "* ScanAll (n)", "* Once"]
|
||||
expected_explain = [" * Produce {n.property1}", " * Filter (n :Node)", " * ScanAll (n)", " * Once"]
|
||||
|
||||
explain_empty = [row["QUERY PLAN"] for row in memgraph.execute_and_fetch(explain_query)]
|
||||
profile_empty = [row["OPERATOR"] for row in memgraph.execute_and_fetch(profile_query)]
|
||||
|
||||
assert explain_empty == expected_explain and profile_empty == expected_profile
|
||||
|
||||
memgraph.execute("CREATE (n:WrongLabel {property1: 2});")
|
||||
|
||||
explain_none_matched = [row["QUERY PLAN"] for row in memgraph.execute_and_fetch(explain_query)]
|
||||
profile_none_matched = [row["OPERATOR"] for row in memgraph.execute_and_fetch(profile_query)]
|
||||
|
||||
assert explain_none_matched == expected_explain and profile_none_matched == expected_profile
|
||||
|
||||
memgraph.execute("CREATE (n:Node {property1: 2});")
|
||||
|
||||
explain_has_match = [row["QUERY PLAN"] for row in memgraph.execute_and_fetch(explain_query)]
|
||||
profile_has_match = [row["OPERATOR"] for row in memgraph.execute_and_fetch(profile_query)]
|
||||
|
||||
assert explain_has_match == expected_explain and profile_has_match == expected_profile
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(pytest.main([__file__, "-rA"]))
|
13
tests/e2e/inspect_query/workloads.yaml
Normal file
13
tests/e2e/inspect_query/workloads.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
inspect_query_cluster: &inspect_query_cluster
|
||||
cluster:
|
||||
main:
|
||||
args: ["--bolt-port", "7687", "--log-level=TRACE"]
|
||||
log_file: "inspect_query.log"
|
||||
setup_queries: []
|
||||
validation_queries: []
|
||||
|
||||
workloads:
|
||||
- name: "Verify that query inspection works"
|
||||
binary: "tests/e2e/pytest_runner.sh"
|
||||
args: ["inspect_query/inspect_query.py"]
|
||||
<<: *inspect_query_cluster
|
Loading…
Reference in New Issue
Block a user