Compare commits
6 Commits
relax-obso
...
T0889-MG-t
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78ec129cde | ||
|
|
be29933414 | ||
|
|
5f2af9050a | ||
|
|
b4f9d4976b | ||
|
|
2302e64e7e | ||
|
|
449fd02b8a |
@@ -398,7 +398,7 @@ cpp<#
|
||||
,@(loop for op in
|
||||
'(or-operator xor-operator and-operator addition-operator
|
||||
subtraction-operator multiplication-operator division-operator
|
||||
mod-operator not-equal-operator equal-operator less-operator
|
||||
mod-operator not-equal-operator less-operator
|
||||
greater-operator less-equal-operator greater-equal-operator
|
||||
in-list-operator subscript-operator)
|
||||
collecting
|
||||
@@ -458,6 +458,33 @@ cpp<#
|
||||
(:clone))))))
|
||||
(define-unary-operators))
|
||||
|
||||
(lcp:define-class equal-operator (binary-operator)
|
||||
((isNullCheckRequired "bool" :initval "false" :scope :public))
|
||||
(:public
|
||||
#>cpp
|
||||
DEFVISITABLE(ExpressionVisitor<TypedValue>);
|
||||
DEFVISITABLE(ExpressionVisitor<void>);
|
||||
|
||||
bool Accept(HierarchicalTreeVisitor &visitor) override {
|
||||
if (visitor.PreVisit(*this)) {
|
||||
expression1_->Accept(visitor) && expression2_->Accept(visitor);
|
||||
}
|
||||
return visitor.PostVisit(*this);
|
||||
}
|
||||
cpp<#)
|
||||
(:protected
|
||||
#>cpp
|
||||
using BinaryOperator::BinaryOperator;
|
||||
EqualOperator(Expression *expression1, Expression *expression2, bool is_nullcheck_required = false)
|
||||
: BinaryOperator(expression1, expression2), isnullcheckrequired_(is_nullcheck_required) {}
|
||||
cpp<#)
|
||||
(:private
|
||||
#>cpp
|
||||
friend class AstStorage;
|
||||
cpp<#)
|
||||
(:serialize (:slk))
|
||||
(:clone))
|
||||
|
||||
(lcp:define-class aggregation (binary-operator)
|
||||
((op "Op" :scope :public)
|
||||
(symbol-pos :int32_t :initval -1 :scope :public
|
||||
|
||||
@@ -2267,9 +2267,9 @@ antlrcpp::Any CypherMainVisitor::visitCaseExpression(MemgraphCypher::CaseExpress
|
||||
Expression *else_expression = ctx->else_expression ? ctx->else_expression->accept(this).as<Expression *>()
|
||||
: storage_->Create<PrimitiveLiteral>(TypedValue());
|
||||
for (auto *alternative : alternatives) {
|
||||
Expression *condition =
|
||||
test_expression ? storage_->Create<EqualOperator>(test_expression, alternative->when_expression->accept(this))
|
||||
: alternative->when_expression->accept(this).as<Expression *>();
|
||||
Expression *condition = test_expression ? storage_->Create<EqualOperator>(
|
||||
test_expression, alternative->when_expression->accept(this), true)
|
||||
: alternative->when_expression->accept(this).as<Expression *>();
|
||||
Expression *then_expression = alternative->then_expression->accept(this);
|
||||
else_expression = storage_->Create<IfOperator>(condition, then_expression, else_expression);
|
||||
}
|
||||
|
||||
@@ -81,7 +81,6 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
BINARY_OPERATOR_VISITOR(DivisionOperator, /, /);
|
||||
BINARY_OPERATOR_VISITOR(ModOperator, %, %);
|
||||
BINARY_OPERATOR_VISITOR(NotEqualOperator, !=, <>);
|
||||
BINARY_OPERATOR_VISITOR(EqualOperator, ==, =);
|
||||
BINARY_OPERATOR_VISITOR(LessOperator, <, <);
|
||||
BINARY_OPERATOR_VISITOR(GreaterOperator, >, >);
|
||||
BINARY_OPERATOR_VISITOR(LessEqualOperator, <=, <=);
|
||||
@@ -94,6 +93,21 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
|
||||
#undef BINARY_OPERATOR_VISITOR
|
||||
#undef UNARY_OPERATOR_VISITOR
|
||||
|
||||
TypedValue Visit(EqualOperator &op) override {
|
||||
auto val1 = op.expression1_->Accept(*this);
|
||||
auto val2 = op.expression2_->Accept(*this);
|
||||
|
||||
try {
|
||||
if (op.isnullcheckrequired_ && val2.IsNull()) {
|
||||
throw QueryRuntimeException("Use the generic form when checking against NULL.");
|
||||
}
|
||||
|
||||
return val1 == val2;
|
||||
} catch (const TypedValueException &) {
|
||||
throw QueryRuntimeException("Invalid types: {} and {} for '='.", val1.type(), val2.type());
|
||||
}
|
||||
}
|
||||
|
||||
TypedValue Visit(AndOperator &op) override {
|
||||
auto value1 = op.expression1_->Accept(*this);
|
||||
if (value1.IsBool() && !value1.ValueBool()) {
|
||||
|
||||
@@ -40,6 +40,7 @@ add_subdirectory(write_procedures)
|
||||
add_subdirectory(magic_functions)
|
||||
add_subdirectory(module_file_manager)
|
||||
add_subdirectory(monitoring_server)
|
||||
add_subdirectory(util_e2e)
|
||||
|
||||
copy_e2e_python_files(pytest_runner pytest_runner.sh "")
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/memgraph-selfsigned.crt DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
5
tests/e2e/util_e2e/CMakeLists.txt
Normal file
5
tests/e2e/util_e2e/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
function(copy_util_e2e_python_files FILE_NAME)
|
||||
copy_e2e_python_files(util_e2e ${FILE_NAME})
|
||||
endfunction()
|
||||
|
||||
copy_util_e2e_python_files(utility_simple.py)
|
||||
40
tests/e2e/util_e2e/utility_simple.py
Normal file
40
tests/e2e/util_e2e/utility_simple.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# Copyright 2022 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 sys
|
||||
import pytest
|
||||
|
||||
|
||||
def test_does_throw_if_null_is_checked_against_in_generic_case():
|
||||
|
||||
connection = mgclient.connect(host="localhost", port=7687)
|
||||
connection.autocommit = True
|
||||
|
||||
cursor = connection.cursor()
|
||||
|
||||
query = """WITH 2 AS name
|
||||
RETURN CASE name
|
||||
WHEN 3 THEN 'works'
|
||||
WHEN null THEN "doesn't work"
|
||||
ELSE 'something went wrong'
|
||||
END"""
|
||||
|
||||
with pytest.raises(mgclient.DatabaseError) as err:
|
||||
cursor.execute(query)
|
||||
|
||||
error_msg = err.value.args[0]
|
||||
assert error_msg == "Use the generic form when checking against NULL."
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(pytest.main([__file__, "-rA"]))
|
||||
13
tests/e2e/util_e2e/workloads.yaml
Normal file
13
tests/e2e/util_e2e/workloads.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
template_cluster: &template_cluster
|
||||
cluster:
|
||||
main:
|
||||
args: ["--bolt-port", "7687", "--log-level=TRACE"]
|
||||
log_file: "util-e2e.log"
|
||||
setup_queries: []
|
||||
validation_queries: []
|
||||
|
||||
workloads:
|
||||
- name: "Utility simple"
|
||||
binary: "tests/e2e/pytest_runner.sh"
|
||||
args: ["util_e2e/utility_simple.py"]
|
||||
<<: *template_cluster
|
||||
@@ -786,6 +786,7 @@ TEST_P(CypherMainVisitorTest, CaseSimpleForm) {
|
||||
ASSERT_TRUE(condition);
|
||||
ast_generator.CheckLiteral(condition->expression1_, 5);
|
||||
ast_generator.CheckLiteral(condition->expression2_, 10);
|
||||
ASSERT_TRUE(condition->isnullcheckrequired_);
|
||||
ast_generator.CheckLiteral(if_operator->then_expression_, 1);
|
||||
ast_generator.CheckLiteral(if_operator->else_expression_, TypedValue());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user