From 876965ae3670b378004e76952b3b7de76e5d0079 Mon Sep 17 00:00:00 2001 From: shirly121 Date: Wed, 12 Feb 2025 17:14:41 +0800 Subject: [PATCH 01/17] init modern schema for type tests --- .../src/test/resources/schema/modern.yaml | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 interactive_engine/compiler/src/test/resources/schema/modern.yaml diff --git a/interactive_engine/compiler/src/test/resources/schema/modern.yaml b/interactive_engine/compiler/src/test/resources/schema/modern.yaml new file mode 100644 index 000000000000..1c3a8f3409bb --- /dev/null +++ b/interactive_engine/compiler/src/test/resources/schema/modern.yaml @@ -0,0 +1,70 @@ +schema: + vertex_types: + - type_name: person + type_id: 0 + properties: + - property_id: 0 + property_name: type0 + property_type: + primitive_type: DT_SIGNED_INT32 + - property_id: 1 + property_name: type1 + property_type: + primitive_type: DT_UNSIGNED_INT32 + - property_id: 2 + property_name: type2 + property_type: + primitive_type: DT_SIGNED_INT64 + - property_id: 3 + property_name: type3 + property_type: + primitive_type: DT_UNSIGNED_INT64 + - property_id: 4 + property_name: type4 + property_type: + primitive_type: DT_BOOL + - property_id: 5 + property_name: type5 + property_type: + primitive_type: DT_FLOAT + - property_id: 6 + property_name: type6 + property_type: + primitive_type: DT_DOUBLE + - property_id: 7 + property_name: type7 + property_type: + string: + long_text: + - property_id: 8 + property_name: type8 + property_type: + string: + char: + fixed_length: 65536 + - property_id: 9 + property_name: type9 + property_type: + string: + var_char: + max_length: 65536 + - property_id: 10 + property_name: type10 + property_type: + temporal: + date32: + - property_id: 11 + property_name: type11 + property_type: + temporal: + timestamp: + primary_keys: + - type0 + edge_types: + - type_name: knows + type_id: 0 + vertex_type_pair_relations: + - source_vertex: person + destination_vertex: person + relation: MANY_TO_MANY + From bbeeddb6e558596f20819add3fa269939d593b60 Mon Sep 17 00:00:00 2001 From: Longbin Lai Date: Wed, 12 Feb 2025 17:28:04 +0800 Subject: [PATCH 02/17] Update modern.yaml --- .../src/test/resources/schema/modern.yaml | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/interactive_engine/compiler/src/test/resources/schema/modern.yaml b/interactive_engine/compiler/src/test/resources/schema/modern.yaml index 1c3a8f3409bb..3e6957050961 100644 --- a/interactive_engine/compiler/src/test/resources/schema/modern.yaml +++ b/interactive_engine/compiler/src/test/resources/schema/modern.yaml @@ -4,62 +4,62 @@ schema: type_id: 0 properties: - property_id: 0 - property_name: type0 + property_name: prop_int32 property_type: primitive_type: DT_SIGNED_INT32 - property_id: 1 - property_name: type1 + property_name: prop_uint32 property_type: primitive_type: DT_UNSIGNED_INT32 - property_id: 2 - property_name: type2 + property_name: prop_int64 property_type: primitive_type: DT_SIGNED_INT64 - property_id: 3 - property_name: type3 + property_name: prop_uint64 property_type: primitive_type: DT_UNSIGNED_INT64 - property_id: 4 - property_name: type4 + property_name: prop_bool property_type: primitive_type: DT_BOOL - property_id: 5 - property_name: type5 + property_name: prop_float property_type: primitive_type: DT_FLOAT - property_id: 6 - property_name: type6 + property_name: prop_double property_type: primitive_type: DT_DOUBLE - property_id: 7 - property_name: type7 + property_name: prop_text property_type: string: long_text: - property_id: 8 - property_name: type8 + property_name: prop_char property_type: string: char: - fixed_length: 65536 + fixed_length: 4 - property_id: 9 - property_name: type9 + property_name: prop_varchar property_type: string: var_char: - max_length: 65536 + max_length: 4 - property_id: 10 - property_name: type10 + property_name: prop_date property_type: temporal: date32: - property_id: 11 - property_name: type11 + property_name: prop_ts property_type: temporal: timestamp: primary_keys: - - type0 + - prop_int32 edge_types: - type_name: knows type_id: 0 From 0859aa2c0488ecc2e1714ca2141b387b60272a7f Mon Sep 17 00:00:00 2001 From: shirly121 Date: Thu, 13 Feb 2025 18:15:00 +0800 Subject: [PATCH 03/17] add test cases and parameters for flex type bench --- .../integration/suite/FlexTypeQueries.java | 1065 +++++++++++++++++ .../resources/flex_bench}/modern.yaml | 30 +- .../src/main/resources/flex_bench/parameters | 59 + 3 files changed, 1139 insertions(+), 15 deletions(-) create mode 100644 interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/integration/suite/FlexTypeQueries.java rename interactive_engine/compiler/src/{test/resources/schema => main/resources/flex_bench}/modern.yaml (73%) create mode 100644 interactive_engine/compiler/src/main/resources/flex_bench/parameters diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/integration/suite/FlexTypeQueries.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/integration/suite/FlexTypeQueries.java new file mode 100644 index 000000000000..c56e8e2144b1 --- /dev/null +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/integration/suite/FlexTypeQueries.java @@ -0,0 +1,1065 @@ +/* + * Copyright 2020 Alibaba Group Holding Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.graphscope.cypher.integration.suite; + +import com.google.common.collect.Maps; + +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; + +public class FlexTypeQueries { + private final Map queryParameters; + + private static class Parameter { + private final String name; + private final List parameters; + private final List results; + + public Parameter(String config) { + throw new UnsupportedOperationException("Not implemented"); + } + } + + public FlexTypeQueries(String inputPath) throws Exception { + List parameters = FileUtils.readLines(new File(inputPath), StandardCharsets.UTF_8); + this.queryParameters = Maps.newHashMap(); + for (String parameter : parameters) { + Parameter param = new Parameter(parameter); + this.queryParameters.put(param.name, param); + } + } + + private class CompareQueries { + /** + * Compare an int32 type property with an int32 literal. + * + * Expected Result: + * The query should return the value of $1. + * @return + */ + public QueryContext compare_int32_int32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32"; + Parameter parameter = queryParameters.get("compare_int32_int32"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare an uint32 type property with an uint32 literal. + * + * Expected Results: + * The query should return the value of $1. + * @return + */ + public QueryContext compare_uint32_uint32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_uint32 = $1\n" + + " RETURN p.prop_uint32"; + Parameter parameter = queryParameters.get("compare_uint32_uint32"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare an uint32 type property with an int32 literal, the literal value is positive and within the range of uint32. + * + * Expected Results: + * The query should return the property value. + * @return + */ + public QueryContext compare_uint32_int32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_uint32 = $1\n" + + " RETURN p.prop_uint32"; + Parameter parameter = queryParameters.get("compare_uint32_int32"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare an uint32 type property with an int32 literal, the literal value is negative and has the same binary representation as the property value. + * + * Expected Results: + * The query should return empty due to integer overflow. + * @return + */ + public QueryContext compare_uint32_int32_overflow_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_uint32 = $1\n" + + " RETURN p.prop_uint32"; + Parameter parameter = queryParameters.get("compare_uint32_int32_overflow"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare an uint64 type property with an uint64 literal. + * + * Expected Results: + * The query should return the value of $1. + * @return + */ + public QueryContext compare_uint64_uint64_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_uint64 = $1\n" + + " RETURN p.prop_uint64"; + Parameter parameter = queryParameters.get("compare_uint64_uint64"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare an int64 type property with an int64 literal. + * + * Expected Results: + * The query should return the value of $1. + * @return + */ + public QueryContext compare_int64_int64_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int64 = $1\n" + + " RETURN p.prop_int64"; + Parameter parameter = queryParameters.get("compare_int64_int64"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare an uint64 type property with an int64 literal, the literal value is positive and within the range of uint64. + * + * Expected Results: + * The query should return the value of $1. + */ + public QueryContext compare_uint64_int64_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_uint64 = $1\n" + + " RETURN p.prop_uint64"; + Parameter parameter = queryParameters.get("compare_uint64_int64"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare an uint64 type property with an int64 literal, the literal value is negative and has the same binary representation as the property value. + * + * Expected Results: + * The query should return empty due to integer overflow. + * @return + */ + public QueryContext compare_uint64_int64_overflow_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int64 = $1\n" + + " RETURN p.prop_int64"; + Parameter parameter = queryParameters.get("compare_uint64_int64_overflow"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare an int32 type property with an int64 literal, the int64 value is within the range of int32. + * + * Expected Results: + * The query should return the value of $1. + * @return + */ + public QueryContext compare_int32_int64_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32"; + Parameter parameter = queryParameters.get("compare_int32_int64"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare an int32 type property with an int64 literal, the literal value is out the range of int32, but the lowest 32-bits are the same with the property value. + * + * Expected Results: + * The query should return empty due to integer overflow. + * @return + */ + public QueryContext compare_int32_int64_overflow_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32"; + Parameter parameter = queryParameters.get("compare_int32_int64_overflow"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare a float type property with a float literal. + * + * Expected Results: + * The query should return the value of $1. + * @return + */ + public QueryContext compare_float_float_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_float = $1\n" + + " RETURN p.prop_float"; + Parameter parameter = queryParameters.get("compare_float_float"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare a double type property with a double literal. + * + * Expected Results: + * The query should return the value of $1. + */ + public QueryContext compare_double_double_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_double = $1\n" + + " RETURN p.prop_double"; + Parameter parameter = queryParameters.get("compare_double_double"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare a float type property with a double literal, they are identical in double representation, like 1.2f and 1.20d. + * + * Expected Results: + * The query should return the property value. + * + * @return + */ + public QueryContext compare_float_double_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_float = $1\n" + + " RETURN p.prop_float"; + Parameter parameter = queryParameters.get("compare_float_double"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare a float type property with a double literal, they are not equal due to precision loss, like 1.2f and 1.23d. + * + * Expected Results: + * The query should return empty. + */ + public QueryContext compare_float_double_loss_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_float = $1\n" + + " RETURN p.prop_float"; + Parameter parameter = queryParameters.get("compare_float_double_loss"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare an int32 type property with a double literal, they are identical in double representation, like 1 and 1.0d + * + * Expected Results: + * The query should return the property value + * @return + */ + public QueryContext compare_int32_double_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32"; + Parameter parameter = queryParameters.get("compare_int32_double"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare a characters type property with a string literal, the literal value is identical to the property value. + * + * Expected Results: + * The query should return the property value. + * @return + */ + public QueryContext compare_char_text_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_char = $1\n" + + " RETURN p.prop_char"; + Parameter parameter = queryParameters.get("compare_char_text"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare a characters type property with a string literal, the literal is longer than the property value. + * + * Expected Results: + * The query should return the property value, the literal is truncated to the length of the property value before comparison. + * @return + */ + public QueryContext compare_char_long_text_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_char = $1\n" + + " RETURN p.prop_char"; + Parameter parameter = queryParameters.get("compare_char_long_text"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare a varchar type property with a string literal, the literal is longer than the property value. + * + * Expected Results: + * The query should return the property value, the literal is truncated to the length of the property value before comparison. + * @return + */ + public QueryContext compare_varchar_long_text_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_varchar = $1\n" + + " RETURN p.prop_varchar"; + Parameter parameter = queryParameters.get("compare_varchar_long_text"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare a string type (unlimited length) with a long text literal, the literal is identical to the property value. + * + * Expected Results: + * The query should return the property value. + * @return + */ + public QueryContext compare_string_long_text_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_text = $1\n" + + " RETURN p.prop_text"; + Parameter parameter = queryParameters.get("compare_string_long_text"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare a date32 type property with an i32 literal. + * + * Expected Results: + * The query should return the property value. + * @return + */ + public QueryContext compare_date32_i32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_date = $1\n" + + " RETURN p.prop_date"; + Parameter parameter = queryParameters.get("compare_date32_i32"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Compare a timestamp type property with an i64 literal. + * + * Expected Results: + * The query should return the property value. + * @return + */ + public QueryContext compare_timestamp_i64_test() { + String query = + "MATCH (p:person)\n" + " WHERE p.prop_ts = $1\n" + " RETURN p.prop_ts"; + Parameter parameter = queryParameters.get("compare_timestamp_i64"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + } + + public class PlusTest { + /** + * Plus an int32 type property with an int32 literal, the sum is within the range of int32. + * + * Expected Results: + * The query should return the sum result of property and $2 + * + * @return + */ + public QueryContext plus_int32_int32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 + $2"; + Parameter parameter = queryParameters.get("plus_int32_int32"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Plus an int32 type property with an int32 literal, the sum is out of the range of int32. + * + * Expected Results: + * The query should throw an exception or return a wrong result due to overflow. + */ + public QueryContext plus_int32_int32_overflow_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 + $2"; + Parameter parameter = queryParameters.get("plus_int32_int32_overflow"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Plus an int32 type property with an uint32 literal, the property value is positive and the sum is within the range of uint32. + * + * Expected Results: + * The query should return an uint32 type value, identical to the sum of property and $2. + */ + public QueryContext plus_int32_uint32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 + $2"; + Parameter parameter = queryParameters.get("plus_int32_uint32"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Plus an int32 type property with an uint32 literal, the property value is negative. + * + * Expected Results: + * The query should throw an exception or return a wrong result due to overflow. + * + * NOTICE to differentiate with the 'plus_int32_int32_test', even though they have the same parameters. + * For example, signed(-100) + signed(100) = 0, but signed(-100) + unsigned(100) = 4294967296, out of the maximum value of UINT32_MAX(4294967295). + * + */ + public QueryContext plus_int32_uint32_overflow_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 + $2"; + Parameter parameter = queryParameters.get("plus_int32_uint32_overflow"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Plus an int32 type property with an int64 literal, the sum is within the range of int64. + * + * Expected Results: + * The query should return an int64 type value, identical to the sum of property and $2 + * @return + */ + public QueryContext plus_int32_int64_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 + $2"; + Parameter parameter = queryParameters.get("plus_int32_int64"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Plus an int32 type property with a double literal. + * + * Expected Results: + * The query should return a double type value, identical to the sum of property and $2. + */ + public QueryContext plus_int32_double_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 + $2"; + Parameter parameter = queryParameters.get("plus_int32_double"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Plus a float type property with a double literal. + * + * Expected Results: + * The query should return a double type value, identical to the sum of property and $2. + */ + public QueryContext plus_float_double_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_float = $1\n" + + " RETURN p.prop_float + $2"; + Parameter parameter = queryParameters.get("plus_float_double"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + } + + public class MinusTest { + /** + * Minus an int32 type property with an int32 literal, the minus is within the range of int32. + * + * Expected Results: + * The query should return the minus result of property and $2 + * + * @return + */ + public QueryContext minus_int32_int32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 - $2"; + Parameter parameter = queryParameters.get("minus_int32_int32"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Minus an int32 type property with an int32 literal, the minus is out of the range of int32. + * + * Expected Results: + * The query should throw an exception or return a wrong result due to overflow. + */ + public QueryContext minus_int32_int32_overflow_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 - $2"; + Parameter parameter = queryParameters.get("minus_int32_int32_overflow"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Minus an int32 type property with an uint32 literal, the property value is positive and the minus is within the range of uint32. + * + * Expected Results: + * The query should return an uint32 type value, identical to the minus of property and $2. + */ + public QueryContext minus_int32_uint32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 - $2"; + Parameter parameter = queryParameters.get("minus_int32_uint32"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Minus an int32 type property with an uint32 literal, the minus is negative, which is out of the range of uint32. + * + * Expected Results: + * The query should throw an exception or return a wrong result due to overflow. + * + */ + public QueryContext minus_int32_uint32_overflow_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 - $2"; + Parameter parameter = queryParameters.get("minus_int32_uint32_overflow"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Minus an int32 type property with an int64 literal, the minus is within the range of int64. + * + * Expected Results: + * The query should return an int64 type value, identical to the minus of property and $2 + * @return + */ + public QueryContext minus_int32_int64_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 - $2"; + Parameter parameter = queryParameters.get("minus_int32_int64"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Minus an int32 type property with a double literal. + * + * Expected Results: + * The query should return a double type value, identical to the minus of property and $2. + */ + public QueryContext minus_int32_double_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 - $2"; + Parameter parameter = queryParameters.get("minus_int32_double"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Minus a float type property with a double literal. + * + * Expected Results: + * The query should return a double type value, identical to the minus of property and $2. + */ + public QueryContext minus_float_double_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_float = $1\n" + + " RETURN p.prop_float - $2"; + Parameter parameter = queryParameters.get("minus_float_double"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + } + + public class MultiplyTest { + /** + * Multiply an int32 type property with an int32 literal, the product is within the range of int32. + * + * Expected Results: + * The query should return the product result of property and $2 + * + * @return + */ + public QueryContext multiply_int32_int32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 * $2"; + Parameter parameter = queryParameters.get("multiply_int32_int32"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Multiply an int32 type property with an int32 literal, the product is out of the range of int32. + * + * Expected Results: + * The query should throw an exception or return a wrong result due to overflow. + */ + public QueryContext multiply_int32_int32_overflow_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 * $2"; + Parameter parameter = queryParameters.get("multiply_int32_int32_overflow"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Multiply an int32 type property with an uint32 literal, the property value is positive and the product is within the range of uint32. + * + * Expected Results: + * The query should return an uint32 type value, identical to the product of property and $2. + */ + public QueryContext multiply_int32_uint32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 * $2"; + Parameter parameter = queryParameters.get("multiply_int32_uint32"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Multiply an int32 type property with an uint32 literal, the property value is negative. + * + * Expected Results: + * The query should throw an exception or return a wrong result due to overflow, i.e. signed(-100) * unsigned(100) is out of uint32 range. + * @return + */ + public QueryContext multiply_int32_uint32_overflow_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 * $2"; + Parameter parameter = queryParameters.get("multiply_int32_uint32_overflow"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Multiply an int32 type property with an int64 literal, the product is within the range of int64. + * + * Expected Results: + * The query should return an int64 type value, identical to the product of property and $2 + * @return + */ + public QueryContext multiply_int32_int64_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 * $2"; + Parameter parameter = queryParameters.get("multiply_int32_int64"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Multiply an int32 type property with a double literal. + * + * Expected Results: + * The query should return a double type value, identical to the product of property and $2. + */ + public QueryContext multiply_int32_double_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 * $2"; + Parameter parameter = queryParameters.get("multiply_int32_double"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Multiply a float type property with a double literal. + * + * Expected Results: + * The query should return a double type value, identical to the product of property and $2. + */ + public QueryContext multiply_float_double_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_float = $1\n" + + " RETURN p.prop_float * $2"; + Parameter parameter = queryParameters.get("multiply_float_double"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + } + + public class DivideTest { + /** + * Divide an int32 type property with an int32 literal, the division is within the range of int32. + * + * Expected Results: + * The query should return the division result of property and $2 + * + * @return + */ + public QueryContext divide_int32_int32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 / $2"; + Parameter parameter = queryParameters.get("divide_int32_int32"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Divide an int32 type property with an int32 literal, the division is out of the maximum value of int32. + *

+ * Expected Results: + * The query should throw an exception or return a wrong result due to overflow. + */ + public QueryContext divide_int32_int32_overflow_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 / $2"; + Parameter parameter = queryParameters.get("divide_int32_int32_overflow"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Divide an int32 type property with an uint32 literal, the division is within the range of uint32. + * + * Expected Results: + * The query should return an uint32 type value, identical to the division of property and $2. + */ + public QueryContext divide_int32_uint32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 / $2"; + Parameter parameter = queryParameters.get("divide_int32_uint32"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Divide an uint32 type property with an int32 literal, the literal value is negative. + * + * Expected Results: + * The query should throw an exception or return a wrong result due to overflow. + * @return + */ + public QueryContext divide_uint32_int32_overflow_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_uint32 = $1\n" + + " RETURN p.prop_uint32 / $2"; + Parameter parameter = queryParameters.get("divide_uint32_int32_overflow"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Divide an int32 type property with an int64 literal, the division is within the range of int64. + * + * Expected Results: + * The query should return an int64 type value, identical to the division of property and $2 + * @return + */ + public QueryContext divide_int32_int64_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 / $2"; + Parameter parameter = queryParameters.get("divide_int32_int64"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Divide an int32 type property with a double literal. + * + * Expected Results: + * The query should return a double type value, identical to the division of property and $2. + */ + public QueryContext divide_int32_double_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32 / $2"; + Parameter parameter = queryParameters.get("divide_int32_double"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Divide a float type property with a double literal. + * + * Expected Results: + * The query should return a double type value, identical to the division of property and $2. + */ + public QueryContext divide_float_double_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_float = $1\n" + + " RETURN p.prop_float / $2"; + Parameter parameter = queryParameters.get("divide_float_double"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + + /** + * Divide a float type property with 0.0d. + * + * Expected Results: + * The query should throw NaN errors. + */ + public QueryContext divide_float_double_NaN_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_float = $1\n" + + " RETURN p.prop_float / $2"; + Parameter parameter = queryParameters.get("divide_float_double_NaN"); + // render the query, replace the $1 with the actual value + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } + } + + /** + * Find 'knows' edges between two persons of specific property values. + * + * Expected Results: + * The query should return the property values for the two persons involved in the 'knows' relationship. + * @return + */ + public QueryContext get_knows_between_two_persons_test() { + String query = + "MATCH (p1:person)-[r:knows]->(p2:person)\n" + + " WHERE p1.prop_int32 = $1 AND p2.prop_int32 = $2\n" + + " RETURN p1.prop_int32, p2.prop_int32"; + Parameter parameter = queryParameters.get("get_knows_between_two_persons"); + // render the query, replace the $1 and $2 with the actual values + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } +} diff --git a/interactive_engine/compiler/src/test/resources/schema/modern.yaml b/interactive_engine/compiler/src/main/resources/flex_bench/modern.yaml similarity index 73% rename from interactive_engine/compiler/src/test/resources/schema/modern.yaml rename to interactive_engine/compiler/src/main/resources/flex_bench/modern.yaml index 1c3a8f3409bb..3e6957050961 100644 --- a/interactive_engine/compiler/src/test/resources/schema/modern.yaml +++ b/interactive_engine/compiler/src/main/resources/flex_bench/modern.yaml @@ -4,62 +4,62 @@ schema: type_id: 0 properties: - property_id: 0 - property_name: type0 + property_name: prop_int32 property_type: primitive_type: DT_SIGNED_INT32 - property_id: 1 - property_name: type1 + property_name: prop_uint32 property_type: primitive_type: DT_UNSIGNED_INT32 - property_id: 2 - property_name: type2 + property_name: prop_int64 property_type: primitive_type: DT_SIGNED_INT64 - property_id: 3 - property_name: type3 + property_name: prop_uint64 property_type: primitive_type: DT_UNSIGNED_INT64 - property_id: 4 - property_name: type4 + property_name: prop_bool property_type: primitive_type: DT_BOOL - property_id: 5 - property_name: type5 + property_name: prop_float property_type: primitive_type: DT_FLOAT - property_id: 6 - property_name: type6 + property_name: prop_double property_type: primitive_type: DT_DOUBLE - property_id: 7 - property_name: type7 + property_name: prop_text property_type: string: long_text: - property_id: 8 - property_name: type8 + property_name: prop_char property_type: string: char: - fixed_length: 65536 + fixed_length: 4 - property_id: 9 - property_name: type9 + property_name: prop_varchar property_type: string: var_char: - max_length: 65536 + max_length: 4 - property_id: 10 - property_name: type10 + property_name: prop_date property_type: temporal: date32: - property_id: 11 - property_name: type11 + property_name: prop_ts property_type: temporal: timestamp: primary_keys: - - type0 + - prop_int32 edge_types: - type_name: knows type_id: 0 diff --git a/interactive_engine/compiler/src/main/resources/flex_bench/parameters b/interactive_engine/compiler/src/main/resources/flex_bench/parameters new file mode 100644 index 000000000000..2e029dd7a3b8 --- /dev/null +++ b/interactive_engine/compiler/src/main/resources/flex_bench/parameters @@ -0,0 +1,59 @@ +test_case_name|parameters|results +compare_int32_int32|12|12 +compare_uint32_uint32|+13|+13 +compare_uint32_int32|12|+12 +compare_uint32_int32_overflow|-12|empty +compare_uint64_uint64|+14L|+14L +compare_int64_int64|14L|14L +compare_uint64_int64|14L|+14L +compare_uint64_int64_overflow|-14L|empty +compare_int32_int64|15L|15 +compare_int32_int64_overflow|2147483648L|empty +compare_float_float|16.0f|16.0f +compare_double_double|16.12d|16.12d +compare_float_double|16.10d|16.1f +compare_float_double_loss|16.12d|empty +compare_int32_double|16.0d|16 +compare_char_text|'abcd'|'abcd' +compare_char_long_text|'abcd'|'abcde' +compare_varchar_long_text|'abcd'|'abcde' +compare_string_long_text|'abcde...'|'abcde...' +compare_date32_i32|1200|1200 +compare_timestamp_i64|1678322400000|1678322400000 + +plus_int32_int32|-12,13|1 +plus_int32_int32_overflow|2147483647,1|overflow +plus_int32_uint32|12,+13|+25 +plus_int32_uint32_overflow|-12,+13|overflow +plus_int32_int64|12,14L|26L +plus_int32_double|12,16.23d|28.23d +plus_float_double|12.0f,16.23d|28.23d + +minus_int32_int32|12,13|-1 +minus_int32_int32_overflow|2147483647,-1|overflow +minus_int32_uint32|13,+12|+1 +minus_int32_uint32_overflow|12,+13|overflow +minus_int32_int64|12,13L|-1L +minus_int32_double|12,13.12d|-1.12d +minus_float_double|12.0f,13.12d|-1.12d + +multiply_int32_int32|1,2|2 +multiply_int32_int32_overflow|2147483647,2|overflow +multiply_int32_uint32|1,+2|+2 +multiply_int32_uint32_overflow|-100,+100|overflow +multiply_int32_int64|1,2L|2L +multiply_int32_double|2,2.12d|4.24d +multiply_float_double|2.0f,2.12d|4.24d + +divide_int32_int32|2,1|2 +divide_int32_int32_overflow|-2147483648,-1|overflow +divide_int32_uint32|2,+1|+2 +divide_uint32_int32_overflow|+1000,-2147483648|overflow +divide_int32_int64|2,1L|2L +divide_int32_double|2,1.12d|1.77d +divide_float_double|2.0f,1.12d|1.78d +divide_float_double_NaN|2.0f,0.0d|NaN + +get_knows_between_two_persons|1,2|1,2 + + From 881372e80e739af78d25360d42ea3a0ac8e930bc Mon Sep 17 00:00:00 2001 From: shirly121 Date: Thu, 13 Feb 2025 19:23:31 +0800 Subject: [PATCH 04/17] minor fix parameters --- .../compiler/src/main/resources/flex_bench/parameters | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interactive_engine/compiler/src/main/resources/flex_bench/parameters b/interactive_engine/compiler/src/main/resources/flex_bench/parameters index 2e029dd7a3b8..73aaed9ccfc3 100644 --- a/interactive_engine/compiler/src/main/resources/flex_bench/parameters +++ b/interactive_engine/compiler/src/main/resources/flex_bench/parameters @@ -15,8 +15,8 @@ compare_float_double|16.10d|16.1f compare_float_double_loss|16.12d|empty compare_int32_double|16.0d|16 compare_char_text|'abcd'|'abcd' -compare_char_long_text|'abcd'|'abcde' -compare_varchar_long_text|'abcd'|'abcde' +compare_char_long_text|'abcde'|'abcd' +compare_varchar_long_text|'abcde'|'abcd' compare_string_long_text|'abcde...'|'abcde...' compare_date32_i32|1200|1200 compare_timestamp_i64|1678322400000|1678322400000 From a1ec3f42537fc7a4d91a63e0e593145b07b799bb Mon Sep 17 00:00:00 2001 From: shirly121 Date: Mon, 17 Feb 2025 21:36:32 +0800 Subject: [PATCH 05/17] refine test cases, parameters and data for flex type --- .../integration/suite/FlexTypeQueries.java | 1065 ----------------- .../src/main/resources/flex_bench/parameters | 59 - .../flex/bench/FlexTypeQueries.java | 1015 ++++++++++++++++ .../integration/flex/bench/FlexTypeTest.java | 113 ++ .../test/resources/flex_bench/data/knows.csv | 4 + .../test/resources/flex_bench/data/person.csv | 6 + .../resources/flex_bench/modern.yaml | 0 .../src/test/resources/flex_bench/parameters | 72 ++ 8 files changed, 1210 insertions(+), 1124 deletions(-) delete mode 100644 interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/integration/suite/FlexTypeQueries.java delete mode 100644 interactive_engine/compiler/src/main/resources/flex_bench/parameters create mode 100644 interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeQueries.java create mode 100644 interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java create mode 100644 interactive_engine/compiler/src/test/resources/flex_bench/data/knows.csv create mode 100644 interactive_engine/compiler/src/test/resources/flex_bench/data/person.csv rename interactive_engine/compiler/src/{main => test}/resources/flex_bench/modern.yaml (100%) create mode 100644 interactive_engine/compiler/src/test/resources/flex_bench/parameters diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/integration/suite/FlexTypeQueries.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/integration/suite/FlexTypeQueries.java deleted file mode 100644 index c56e8e2144b1..000000000000 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/integration/suite/FlexTypeQueries.java +++ /dev/null @@ -1,1065 +0,0 @@ -/* - * Copyright 2020 Alibaba Group Holding Limited. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.graphscope.cypher.integration.suite; - -import com.google.common.collect.Maps; - -import org.apache.commons.io.FileUtils; - -import java.io.File; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Map; - -public class FlexTypeQueries { - private final Map queryParameters; - - private static class Parameter { - private final String name; - private final List parameters; - private final List results; - - public Parameter(String config) { - throw new UnsupportedOperationException("Not implemented"); - } - } - - public FlexTypeQueries(String inputPath) throws Exception { - List parameters = FileUtils.readLines(new File(inputPath), StandardCharsets.UTF_8); - this.queryParameters = Maps.newHashMap(); - for (String parameter : parameters) { - Parameter param = new Parameter(parameter); - this.queryParameters.put(param.name, param); - } - } - - private class CompareQueries { - /** - * Compare an int32 type property with an int32 literal. - * - * Expected Result: - * The query should return the value of $1. - * @return - */ - public QueryContext compare_int32_int32_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32"; - Parameter parameter = queryParameters.get("compare_int32_int32"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare an uint32 type property with an uint32 literal. - * - * Expected Results: - * The query should return the value of $1. - * @return - */ - public QueryContext compare_uint32_uint32_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_uint32 = $1\n" - + " RETURN p.prop_uint32"; - Parameter parameter = queryParameters.get("compare_uint32_uint32"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare an uint32 type property with an int32 literal, the literal value is positive and within the range of uint32. - * - * Expected Results: - * The query should return the property value. - * @return - */ - public QueryContext compare_uint32_int32_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_uint32 = $1\n" - + " RETURN p.prop_uint32"; - Parameter parameter = queryParameters.get("compare_uint32_int32"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare an uint32 type property with an int32 literal, the literal value is negative and has the same binary representation as the property value. - * - * Expected Results: - * The query should return empty due to integer overflow. - * @return - */ - public QueryContext compare_uint32_int32_overflow_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_uint32 = $1\n" - + " RETURN p.prop_uint32"; - Parameter parameter = queryParameters.get("compare_uint32_int32_overflow"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare an uint64 type property with an uint64 literal. - * - * Expected Results: - * The query should return the value of $1. - * @return - */ - public QueryContext compare_uint64_uint64_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_uint64 = $1\n" - + " RETURN p.prop_uint64"; - Parameter parameter = queryParameters.get("compare_uint64_uint64"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare an int64 type property with an int64 literal. - * - * Expected Results: - * The query should return the value of $1. - * @return - */ - public QueryContext compare_int64_int64_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int64 = $1\n" - + " RETURN p.prop_int64"; - Parameter parameter = queryParameters.get("compare_int64_int64"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare an uint64 type property with an int64 literal, the literal value is positive and within the range of uint64. - * - * Expected Results: - * The query should return the value of $1. - */ - public QueryContext compare_uint64_int64_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_uint64 = $1\n" - + " RETURN p.prop_uint64"; - Parameter parameter = queryParameters.get("compare_uint64_int64"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare an uint64 type property with an int64 literal, the literal value is negative and has the same binary representation as the property value. - * - * Expected Results: - * The query should return empty due to integer overflow. - * @return - */ - public QueryContext compare_uint64_int64_overflow_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int64 = $1\n" - + " RETURN p.prop_int64"; - Parameter parameter = queryParameters.get("compare_uint64_int64_overflow"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare an int32 type property with an int64 literal, the int64 value is within the range of int32. - * - * Expected Results: - * The query should return the value of $1. - * @return - */ - public QueryContext compare_int32_int64_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32"; - Parameter parameter = queryParameters.get("compare_int32_int64"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare an int32 type property with an int64 literal, the literal value is out the range of int32, but the lowest 32-bits are the same with the property value. - * - * Expected Results: - * The query should return empty due to integer overflow. - * @return - */ - public QueryContext compare_int32_int64_overflow_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32"; - Parameter parameter = queryParameters.get("compare_int32_int64_overflow"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare a float type property with a float literal. - * - * Expected Results: - * The query should return the value of $1. - * @return - */ - public QueryContext compare_float_float_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_float = $1\n" - + " RETURN p.prop_float"; - Parameter parameter = queryParameters.get("compare_float_float"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare a double type property with a double literal. - * - * Expected Results: - * The query should return the value of $1. - */ - public QueryContext compare_double_double_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_double = $1\n" - + " RETURN p.prop_double"; - Parameter parameter = queryParameters.get("compare_double_double"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare a float type property with a double literal, they are identical in double representation, like 1.2f and 1.20d. - * - * Expected Results: - * The query should return the property value. - * - * @return - */ - public QueryContext compare_float_double_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_float = $1\n" - + " RETURN p.prop_float"; - Parameter parameter = queryParameters.get("compare_float_double"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare a float type property with a double literal, they are not equal due to precision loss, like 1.2f and 1.23d. - * - * Expected Results: - * The query should return empty. - */ - public QueryContext compare_float_double_loss_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_float = $1\n" - + " RETURN p.prop_float"; - Parameter parameter = queryParameters.get("compare_float_double_loss"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare an int32 type property with a double literal, they are identical in double representation, like 1 and 1.0d - * - * Expected Results: - * The query should return the property value - * @return - */ - public QueryContext compare_int32_double_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32"; - Parameter parameter = queryParameters.get("compare_int32_double"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare a characters type property with a string literal, the literal value is identical to the property value. - * - * Expected Results: - * The query should return the property value. - * @return - */ - public QueryContext compare_char_text_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_char = $1\n" - + " RETURN p.prop_char"; - Parameter parameter = queryParameters.get("compare_char_text"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare a characters type property with a string literal, the literal is longer than the property value. - * - * Expected Results: - * The query should return the property value, the literal is truncated to the length of the property value before comparison. - * @return - */ - public QueryContext compare_char_long_text_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_char = $1\n" - + " RETURN p.prop_char"; - Parameter parameter = queryParameters.get("compare_char_long_text"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare a varchar type property with a string literal, the literal is longer than the property value. - * - * Expected Results: - * The query should return the property value, the literal is truncated to the length of the property value before comparison. - * @return - */ - public QueryContext compare_varchar_long_text_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_varchar = $1\n" - + " RETURN p.prop_varchar"; - Parameter parameter = queryParameters.get("compare_varchar_long_text"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare a string type (unlimited length) with a long text literal, the literal is identical to the property value. - * - * Expected Results: - * The query should return the property value. - * @return - */ - public QueryContext compare_string_long_text_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_text = $1\n" - + " RETURN p.prop_text"; - Parameter parameter = queryParameters.get("compare_string_long_text"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare a date32 type property with an i32 literal. - * - * Expected Results: - * The query should return the property value. - * @return - */ - public QueryContext compare_date32_i32_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_date = $1\n" - + " RETURN p.prop_date"; - Parameter parameter = queryParameters.get("compare_date32_i32"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Compare a timestamp type property with an i64 literal. - * - * Expected Results: - * The query should return the property value. - * @return - */ - public QueryContext compare_timestamp_i64_test() { - String query = - "MATCH (p:person)\n" + " WHERE p.prop_ts = $1\n" + " RETURN p.prop_ts"; - Parameter parameter = queryParameters.get("compare_timestamp_i64"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - } - - public class PlusTest { - /** - * Plus an int32 type property with an int32 literal, the sum is within the range of int32. - * - * Expected Results: - * The query should return the sum result of property and $2 - * - * @return - */ - public QueryContext plus_int32_int32_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 + $2"; - Parameter parameter = queryParameters.get("plus_int32_int32"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Plus an int32 type property with an int32 literal, the sum is out of the range of int32. - * - * Expected Results: - * The query should throw an exception or return a wrong result due to overflow. - */ - public QueryContext plus_int32_int32_overflow_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 + $2"; - Parameter parameter = queryParameters.get("plus_int32_int32_overflow"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Plus an int32 type property with an uint32 literal, the property value is positive and the sum is within the range of uint32. - * - * Expected Results: - * The query should return an uint32 type value, identical to the sum of property and $2. - */ - public QueryContext plus_int32_uint32_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 + $2"; - Parameter parameter = queryParameters.get("plus_int32_uint32"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Plus an int32 type property with an uint32 literal, the property value is negative. - * - * Expected Results: - * The query should throw an exception or return a wrong result due to overflow. - * - * NOTICE to differentiate with the 'plus_int32_int32_test', even though they have the same parameters. - * For example, signed(-100) + signed(100) = 0, but signed(-100) + unsigned(100) = 4294967296, out of the maximum value of UINT32_MAX(4294967295). - * - */ - public QueryContext plus_int32_uint32_overflow_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 + $2"; - Parameter parameter = queryParameters.get("plus_int32_uint32_overflow"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Plus an int32 type property with an int64 literal, the sum is within the range of int64. - * - * Expected Results: - * The query should return an int64 type value, identical to the sum of property and $2 - * @return - */ - public QueryContext plus_int32_int64_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 + $2"; - Parameter parameter = queryParameters.get("plus_int32_int64"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Plus an int32 type property with a double literal. - * - * Expected Results: - * The query should return a double type value, identical to the sum of property and $2. - */ - public QueryContext plus_int32_double_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 + $2"; - Parameter parameter = queryParameters.get("plus_int32_double"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Plus a float type property with a double literal. - * - * Expected Results: - * The query should return a double type value, identical to the sum of property and $2. - */ - public QueryContext plus_float_double_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_float = $1\n" - + " RETURN p.prop_float + $2"; - Parameter parameter = queryParameters.get("plus_float_double"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - } - - public class MinusTest { - /** - * Minus an int32 type property with an int32 literal, the minus is within the range of int32. - * - * Expected Results: - * The query should return the minus result of property and $2 - * - * @return - */ - public QueryContext minus_int32_int32_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 - $2"; - Parameter parameter = queryParameters.get("minus_int32_int32"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Minus an int32 type property with an int32 literal, the minus is out of the range of int32. - * - * Expected Results: - * The query should throw an exception or return a wrong result due to overflow. - */ - public QueryContext minus_int32_int32_overflow_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 - $2"; - Parameter parameter = queryParameters.get("minus_int32_int32_overflow"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Minus an int32 type property with an uint32 literal, the property value is positive and the minus is within the range of uint32. - * - * Expected Results: - * The query should return an uint32 type value, identical to the minus of property and $2. - */ - public QueryContext minus_int32_uint32_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 - $2"; - Parameter parameter = queryParameters.get("minus_int32_uint32"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Minus an int32 type property with an uint32 literal, the minus is negative, which is out of the range of uint32. - * - * Expected Results: - * The query should throw an exception or return a wrong result due to overflow. - * - */ - public QueryContext minus_int32_uint32_overflow_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 - $2"; - Parameter parameter = queryParameters.get("minus_int32_uint32_overflow"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Minus an int32 type property with an int64 literal, the minus is within the range of int64. - * - * Expected Results: - * The query should return an int64 type value, identical to the minus of property and $2 - * @return - */ - public QueryContext minus_int32_int64_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 - $2"; - Parameter parameter = queryParameters.get("minus_int32_int64"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Minus an int32 type property with a double literal. - * - * Expected Results: - * The query should return a double type value, identical to the minus of property and $2. - */ - public QueryContext minus_int32_double_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 - $2"; - Parameter parameter = queryParameters.get("minus_int32_double"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Minus a float type property with a double literal. - * - * Expected Results: - * The query should return a double type value, identical to the minus of property and $2. - */ - public QueryContext minus_float_double_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_float = $1\n" - + " RETURN p.prop_float - $2"; - Parameter parameter = queryParameters.get("minus_float_double"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - } - - public class MultiplyTest { - /** - * Multiply an int32 type property with an int32 literal, the product is within the range of int32. - * - * Expected Results: - * The query should return the product result of property and $2 - * - * @return - */ - public QueryContext multiply_int32_int32_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 * $2"; - Parameter parameter = queryParameters.get("multiply_int32_int32"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Multiply an int32 type property with an int32 literal, the product is out of the range of int32. - * - * Expected Results: - * The query should throw an exception or return a wrong result due to overflow. - */ - public QueryContext multiply_int32_int32_overflow_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 * $2"; - Parameter parameter = queryParameters.get("multiply_int32_int32_overflow"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Multiply an int32 type property with an uint32 literal, the property value is positive and the product is within the range of uint32. - * - * Expected Results: - * The query should return an uint32 type value, identical to the product of property and $2. - */ - public QueryContext multiply_int32_uint32_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 * $2"; - Parameter parameter = queryParameters.get("multiply_int32_uint32"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Multiply an int32 type property with an uint32 literal, the property value is negative. - * - * Expected Results: - * The query should throw an exception or return a wrong result due to overflow, i.e. signed(-100) * unsigned(100) is out of uint32 range. - * @return - */ - public QueryContext multiply_int32_uint32_overflow_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 * $2"; - Parameter parameter = queryParameters.get("multiply_int32_uint32_overflow"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Multiply an int32 type property with an int64 literal, the product is within the range of int64. - * - * Expected Results: - * The query should return an int64 type value, identical to the product of property and $2 - * @return - */ - public QueryContext multiply_int32_int64_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 * $2"; - Parameter parameter = queryParameters.get("multiply_int32_int64"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Multiply an int32 type property with a double literal. - * - * Expected Results: - * The query should return a double type value, identical to the product of property and $2. - */ - public QueryContext multiply_int32_double_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 * $2"; - Parameter parameter = queryParameters.get("multiply_int32_double"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Multiply a float type property with a double literal. - * - * Expected Results: - * The query should return a double type value, identical to the product of property and $2. - */ - public QueryContext multiply_float_double_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_float = $1\n" - + " RETURN p.prop_float * $2"; - Parameter parameter = queryParameters.get("multiply_float_double"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - } - - public class DivideTest { - /** - * Divide an int32 type property with an int32 literal, the division is within the range of int32. - * - * Expected Results: - * The query should return the division result of property and $2 - * - * @return - */ - public QueryContext divide_int32_int32_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 / $2"; - Parameter parameter = queryParameters.get("divide_int32_int32"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Divide an int32 type property with an int32 literal, the division is out of the maximum value of int32. - *

- * Expected Results: - * The query should throw an exception or return a wrong result due to overflow. - */ - public QueryContext divide_int32_int32_overflow_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 / $2"; - Parameter parameter = queryParameters.get("divide_int32_int32_overflow"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Divide an int32 type property with an uint32 literal, the division is within the range of uint32. - * - * Expected Results: - * The query should return an uint32 type value, identical to the division of property and $2. - */ - public QueryContext divide_int32_uint32_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 / $2"; - Parameter parameter = queryParameters.get("divide_int32_uint32"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Divide an uint32 type property with an int32 literal, the literal value is negative. - * - * Expected Results: - * The query should throw an exception or return a wrong result due to overflow. - * @return - */ - public QueryContext divide_uint32_int32_overflow_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_uint32 = $1\n" - + " RETURN p.prop_uint32 / $2"; - Parameter parameter = queryParameters.get("divide_uint32_int32_overflow"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Divide an int32 type property with an int64 literal, the division is within the range of int64. - * - * Expected Results: - * The query should return an int64 type value, identical to the division of property and $2 - * @return - */ - public QueryContext divide_int32_int64_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 / $2"; - Parameter parameter = queryParameters.get("divide_int32_int64"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Divide an int32 type property with a double literal. - * - * Expected Results: - * The query should return a double type value, identical to the division of property and $2. - */ - public QueryContext divide_int32_double_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_int32 = $1\n" - + " RETURN p.prop_int32 / $2"; - Parameter parameter = queryParameters.get("divide_int32_double"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Divide a float type property with a double literal. - * - * Expected Results: - * The query should return a double type value, identical to the division of property and $2. - */ - public QueryContext divide_float_double_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_float = $1\n" - + " RETURN p.prop_float / $2"; - Parameter parameter = queryParameters.get("divide_float_double"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - - /** - * Divide a float type property with 0.0d. - * - * Expected Results: - * The query should throw NaN errors. - */ - public QueryContext divide_float_double_NaN_test() { - String query = - "MATCH (p:person)\n" - + " WHERE p.prop_float = $1\n" - + " RETURN p.prop_float / $2"; - Parameter parameter = queryParameters.get("divide_float_double_NaN"); - // render the query, replace the $1 with the actual value - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } - } - - /** - * Find 'knows' edges between two persons of specific property values. - * - * Expected Results: - * The query should return the property values for the two persons involved in the 'knows' relationship. - * @return - */ - public QueryContext get_knows_between_two_persons_test() { - String query = - "MATCH (p1:person)-[r:knows]->(p2:person)\n" - + " WHERE p1.prop_int32 = $1 AND p2.prop_int32 = $2\n" - + " RETURN p1.prop_int32, p2.prop_int32"; - Parameter parameter = queryParameters.get("get_knows_between_two_persons"); - // render the query, replace the $1 and $2 with the actual values - for (int i = 0; i < parameter.parameters.size(); i++) { - query = query.replace("$" + (i + 1), parameter.parameters.get(i)); - } - return new QueryContext(query, parameter.results); - } -} diff --git a/interactive_engine/compiler/src/main/resources/flex_bench/parameters b/interactive_engine/compiler/src/main/resources/flex_bench/parameters deleted file mode 100644 index 73aaed9ccfc3..000000000000 --- a/interactive_engine/compiler/src/main/resources/flex_bench/parameters +++ /dev/null @@ -1,59 +0,0 @@ -test_case_name|parameters|results -compare_int32_int32|12|12 -compare_uint32_uint32|+13|+13 -compare_uint32_int32|12|+12 -compare_uint32_int32_overflow|-12|empty -compare_uint64_uint64|+14L|+14L -compare_int64_int64|14L|14L -compare_uint64_int64|14L|+14L -compare_uint64_int64_overflow|-14L|empty -compare_int32_int64|15L|15 -compare_int32_int64_overflow|2147483648L|empty -compare_float_float|16.0f|16.0f -compare_double_double|16.12d|16.12d -compare_float_double|16.10d|16.1f -compare_float_double_loss|16.12d|empty -compare_int32_double|16.0d|16 -compare_char_text|'abcd'|'abcd' -compare_char_long_text|'abcde'|'abcd' -compare_varchar_long_text|'abcde'|'abcd' -compare_string_long_text|'abcde...'|'abcde...' -compare_date32_i32|1200|1200 -compare_timestamp_i64|1678322400000|1678322400000 - -plus_int32_int32|-12,13|1 -plus_int32_int32_overflow|2147483647,1|overflow -plus_int32_uint32|12,+13|+25 -plus_int32_uint32_overflow|-12,+13|overflow -plus_int32_int64|12,14L|26L -plus_int32_double|12,16.23d|28.23d -plus_float_double|12.0f,16.23d|28.23d - -minus_int32_int32|12,13|-1 -minus_int32_int32_overflow|2147483647,-1|overflow -minus_int32_uint32|13,+12|+1 -minus_int32_uint32_overflow|12,+13|overflow -minus_int32_int64|12,13L|-1L -minus_int32_double|12,13.12d|-1.12d -minus_float_double|12.0f,13.12d|-1.12d - -multiply_int32_int32|1,2|2 -multiply_int32_int32_overflow|2147483647,2|overflow -multiply_int32_uint32|1,+2|+2 -multiply_int32_uint32_overflow|-100,+100|overflow -multiply_int32_int64|1,2L|2L -multiply_int32_double|2,2.12d|4.24d -multiply_float_double|2.0f,2.12d|4.24d - -divide_int32_int32|2,1|2 -divide_int32_int32_overflow|-2147483648,-1|overflow -divide_int32_uint32|2,+1|+2 -divide_uint32_int32_overflow|+1000,-2147483648|overflow -divide_int32_int64|2,1L|2L -divide_int32_double|2,1.12d|1.77d -divide_float_double|2.0f,1.12d|1.78d -divide_float_double_NaN|2.0f,0.0d|NaN - -get_knows_between_two_persons|1,2|1,2 - - diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeQueries.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeQueries.java new file mode 100644 index 000000000000..ff30db4898b6 --- /dev/null +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeQueries.java @@ -0,0 +1,1015 @@ +/* + * Copyright 2020 Alibaba Group Holding Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.graphscope.cypher.integration.flex.bench; + +import com.alibaba.graphscope.cypher.integration.suite.QueryContext; +import com.google.common.base.Preconditions; +import com.google.common.collect.Maps; + +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class FlexTypeQueries { + private final Map queryParameters; + + private static class Parameter { + private final String name; + private final List parameters; + private final List results; + + public Parameter(String line) { + String[] parts = line.split("\\|"); + Preconditions.checkArgument(parts.length >= 3, "invalid parameter line: " + line); + this.name = parts[0].trim(); + this.parameters = + List.of(parts[1].trim().split(",")).stream() + .map(k -> k.trim()) + .collect(Collectors.toList()); + this.results = + List.of(parts[2].trim().split(",")).stream() + .map(k -> k.trim()) + .collect(Collectors.toList()); + } + + public String render(String template) { + for (int i = 1; i <= parameters.size(); i++) { + template = template.replaceAll("\\$" + i, parameters.get(i - 1)); + } + return template; + } + } + + public FlexTypeQueries(String inputPath) throws Exception { + List parameters = FileUtils.readLines(new File(inputPath), StandardCharsets.UTF_8); + this.queryParameters = Maps.newHashMap(); + for (String parameter : parameters) { + if (parameter.trim().isEmpty() || parameter.startsWith("//")) continue; + Parameter param = new Parameter(parameter); + this.queryParameters.put(param.name, param); + } + } + + public CompareTest getCompare() { + return new CompareTest(); + } + + public PlusTest getPlus() { + return new PlusTest(); + } + + public MinusTest getMinus() { + return new MinusTest(); + } + + public MultiplyTest getMultiply() { + return new MultiplyTest(); + } + + public DivideTest getDivide() { + return new DivideTest(); + } + + // Assign type to the literal value with prefix or suffix characters. + // i.e. 1 denote int32, +1 denote uint32, 1L denote int64, +1L denote uint64, 1.0d denote + // double, 1.0f denote float. + public class CompareTest { + /** + * Compare an int32 type property with an int32 literal. + * + * Expected Result: + * The query should return the property value. + * @return + */ + public QueryContext compare_int32_int32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32"; + Parameter parameter = queryParameters.get("compare_int32_int32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare a uint32 type property with a uint32 literal. + * + * Expected Result: + * The query should return the property value. + * @return + */ + public QueryContext compare_uint32_uint32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_uint32 = $1\n" + + " RETURN p.prop_uint32"; + Parameter parameter = queryParameters.get("compare_uint32_uint32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare a uint32 type property with an int32 literal. + * + * Expected Result: + * The query should return the property value. + * @return + */ + public QueryContext compare_uint32_int32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_uint32 = $1\n" + + " RETURN p.prop_uint32"; + Parameter parameter = queryParameters.get("compare_uint32_int32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare a uint32 type property with an int32 literal, where the int32 literal is negative + * and has the same binary representation as the uint32 property value. + * + * Expected Result: + * The query should return empty due to integer overflow. + * @return + */ + public QueryContext compare_uint32_int32_overflow_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_uint32 = $1\n" + + " RETURN p.prop_uint32"; + Parameter parameter = queryParameters.get("compare_uint32_int32_overflow"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare a uint64 type property with a uint64 literal. + * + * Expected Result: + * The query should return the property value. + * @return + */ + public QueryContext compare_uint64_uint64_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_uint64 = $1\n" + + " RETURN p.prop_uint64"; + Parameter parameter = queryParameters.get("compare_uint64_uint64"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare an int64 type property with an int64 literal. + * + * Expected Result: + * The query should return the property value. + * @return + */ + public QueryContext compare_int64_int64_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int64 = $1\n" + + " RETURN p.prop_int64"; + Parameter parameter = queryParameters.get("compare_int64_int64"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare a uint64 type property with an int64 literal. + * + * Expected Result: + * The query should return the property value. + * @return + */ + public QueryContext compare_uint64_int64_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_uint64 = $1\n" + + " RETURN p.prop_uint64"; + Parameter parameter = queryParameters.get("compare_uint64_int64"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare a uint64 type property with an int64 literal, where the int64 literal is negative + * and has the same binary representation as the uint64 property value. + * + * Expected Result: + * The query should return empty due to integer overflow. + * @return + */ + public QueryContext compare_uint64_int64_overflow_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_uint64 = $1\n" + + " RETURN p.prop_uint64"; + Parameter parameter = queryParameters.get("compare_uint64_int64_overflow"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare an int32 type property with an int64 literal. + * + * Expected Result: + * The query should return the property value. + * @return + */ + public QueryContext compare_int32_int64_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32"; + Parameter parameter = queryParameters.get("compare_int32_int64"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare an int32 type property with an int64 literal that exceeds the range of int32. The int64 after overflow has the same binary representation as the int32 value. + * + * Expected Result: + * The query should return empty due to overflow. + * @return + */ + public QueryContext compare_int32_int64_overflow_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32"; + Parameter parameter = queryParameters.get("compare_int32_int64_overflow"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare a float type property with a float literal. + * + * Expected Result: + * The query should return the property value. + * @return + */ + public QueryContext compare_float_float_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_float = $1\n" + + " RETURN p.prop_float"; + Parameter parameter = queryParameters.get("compare_float_float"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare a double type property with a double literal. + * + * Expected Result: + * The query should return the property value. + * @return + */ + public QueryContext compare_double_double_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_double = $1\n" + + " RETURN p.prop_double"; + Parameter parameter = queryParameters.get("compare_double_double"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare a float type property with a double literal. + * + * Expected Result: + * The query should return the float value as the result. + * @return + */ + public QueryContext compare_float_double_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_float = $1\n" + + " RETURN p.prop_float"; + Parameter parameter = queryParameters.get("compare_float_double"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare a float type property with a double literal, where the double literal has more precision + * than the float property, leading to precision loss. + * + * Expected Result: + * The query should return empty due to precision loss. + * @return + */ + public QueryContext compare_float_double_loss_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_float = $1\n" + + " RETURN p.prop_float"; + Parameter parameter = queryParameters.get("compare_float_double_loss"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare an int32 type property with a double literal. + * + * Expected Result: + * The query should return the property value as an int32. + * @return + */ + public QueryContext compare_int32_double_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_int32 = $1\n" + + " RETURN p.prop_int32"; + Parameter parameter = queryParameters.get("compare_int32_double"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare a characters type property with a string literal, the literal value is identical to the property value. + * + * Expected Results: + * The query should return the property value. + * @return + */ + public QueryContext compare_char_text_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_char = $1\n" + + " RETURN p.prop_char"; + Parameter parameter = queryParameters.get("compare_char_text"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare a characters type property with a string literal, the literal is longer than the property value. + * + * Expected Results: + * The query should return the property value, the literal has been truncated to the length of the property value before comparison. + * @return + */ + public QueryContext compare_char_long_text_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_char = $1\n" + + " RETURN p.prop_char"; + Parameter parameter = queryParameters.get("compare_char_long_text"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare a varchar type property with a string literal, the literal is longer than the property value. + * + * Expected Results: + * The query should return the property value, the literal has been truncated to the length of the property value before comparison. + * @return + */ + public QueryContext compare_varchar_long_text_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_varchar = $1\n" + + " RETURN p.prop_varchar"; + Parameter parameter = queryParameters.get("compare_varchar_long_text"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare an unlimited length type property with a long text literal, the literal is identical to the property value. + * + * Expected Results: + * The query should return the property value. + * @return + */ + public QueryContext compare_string_long_text_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_text = $1\n" + + " RETURN p.prop_text"; + Parameter parameter = queryParameters.get("compare_string_long_text"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare a date32 type property with an i32 literal. + * + * Expected Results: + * The query should return the property value. + * @return + */ + public QueryContext compare_date32_i32_test() { + String query = + "MATCH (p:person)\n" + + " WHERE p.prop_date = $1\n" + + " RETURN p.prop_date"; + Parameter parameter = queryParameters.get("compare_date32_i32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Compare a timestamp type property with an i64 literal. + * + * Expected Results: + * The query should return the property value. + * @return + */ + public QueryContext compare_timestamp_i64_test() { + String query = + "MATCH (p:person)\n" + " WHERE p.prop_ts = $1\n" + " RETURN p.prop_ts"; + Parameter parameter = queryParameters.get("compare_timestamp_i64"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + } + + public class PlusTest { + + // plus_int32_int32|12,13|25 + /** + * Plus an int32 value with an int32 value, the sum is within the range of int32. + * + * Expected Results: + * The query should return an int32 type value, identical to the sum of $1 and $2. + */ + public QueryContext plus_int32_int32_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 + $2"; + Parameter parameter = queryParameters.get("plus_int32_int32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // plus_int32_int32_overflow|2147483647,1|overflow + /** + * Plus an int32 value with an int32 value, the sum exceeds the range of int32. + * + * Expected Results: + * The query should throw an overflow exception due to int32 overflow. + */ + public QueryContext plus_int32_int32_overflow_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 + $2"; + Parameter parameter = queryParameters.get("plus_int32_int32_overflow"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // plus_int32_uint32_int32|12,+13|25 + /** + * Plus an int32 value with an uint32 value, the sum is within the range of int32. + * + * Expected Results: + * The query should return an int32 type value, identical to the sum of $1 and $2. + */ + public QueryContext plus_int32_uint32_int32_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 + $2"; + Parameter parameter = queryParameters.get("plus_int32_uint32_int32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // plus_int32_uint32_uint32|10,+2147483647|+2147483657 + /** + * Plus an int32 value with an uint32 value, the sum is out of range of int32 but within the range of uint32. + * + * Expected Results: + * The query should return a uint32 type value, identical to the sum of $1 and $2. + */ + public QueryContext plus_int32_uint32_uint32_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 + $2"; + Parameter parameter = queryParameters.get("plus_int32_uint32_uint32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // plus_int32_uint32_overflow|1,+4294967295|overflow + /** + * Plus an int32 value with an uint32 value, the sum exceeds the range of uint32. + * + * Expected Results: + * The query should throw an overflow exception due to uint32 overflow. + */ + public QueryContext plus_int32_uint32_overflow_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 + $2"; + Parameter parameter = queryParameters.get("plus_int32_uint32_overflow"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // plus_int32_int64|12,14L|26L + /** + * Plus an int32 value with an int64 value, the sum is within the range of int64. + * + * Expected Results: + * The query should return an int64 type value, identical to the sum of $1 and $2. + */ + public QueryContext plus_int32_int64_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 + $2"; + Parameter parameter = queryParameters.get("plus_int32_int64"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // plus_int32_int64_overflow|10,9223372036854775807L|overflow + /** + * Plus an int32 value with an int64 value, the sum exceeds the range of int64. + * + * Expected Results: + * The query should throw an overflow exception due to int64 overflow. + */ + public QueryContext plus_int32_int64_overflow_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 + $2"; + Parameter parameter = queryParameters.get("plus_int32_int64_overflow"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Plus an int32 value with a double value. + * + * Expected Results: + * The query should return a double type value, identical to the sum of $1 and $2. + */ + public QueryContext plus_int32_double_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 + $2"; + Parameter parameter = queryParameters.get("plus_int32_double"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Plus a float type value with a double value. + * + * Expected Results: + * The query should return a double type value, identical to the sum of $1 and $2. + */ + public QueryContext plus_float_double_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 + $2"; + Parameter parameter = queryParameters.get("plus_float_double"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + } + + public class MinusTest { + + // divide_int32_int32|2,1|2 + /** + * Divide an int32 value by an int32 value, the result is within the range of int32. + * + * Expected Results: + * The query should return an int32 type value, identical to the quotient of $1 and $2. + */ + public QueryContext divide_int32_int32_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_int32_int32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_int32_int32_overflow|-2147483648,-1|overflow + /** + * Divide an int32 value by an int32 value, the result exceeds the range of int32. + * + * Expected Results: + * The query should throw an overflow exception due to int32 overflow. + */ + public QueryContext divide_int32_int32_overflow_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_int32_int32_overflow"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_int32_uint32_int32|2,+1|2 + /** + * Divide an int32 value by an uint32 value, the result is within the range of int32. + * + * Expected Results: + * The query should return an int32 type value, identical to the quotient of $1 and $2. + */ + public QueryContext divide_int32_uint32_int32_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_int32_uint32_int32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_uint32_int32_uint32|+4294967295,1|+4294967295 + /** + * Divide an uint32 value by an int32 value, the result is out of the range of int32 but within the range of uint32. + * + * Expected Results: + * The query should return a uint32 type value, identical to the quotient of $1 and $2. + */ + public QueryContext divide_uint32_int32_uint32_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_uint32_int32_uint32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_uint32_int32_overflow|+4294967295,-1|overflow + /** + * Divide an uint32 value by a negative int32 value, the result exceeds the range of int32 (SIGNED_INT32_MIN). + * + * Expected Results: + * The query should throw an overflow exception due to int32 overflow. + */ + public QueryContext divide_uint32_int32_overflow_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_uint32_int32_overflow"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_int32_int64|2,1L|2L + /** + * Divide an int32 value by an int64 value, the result is within the range of int64. + * + * Expected Results: + * The query should return an int64 type value, identical to the quotient of $1 and $2. + */ + public QueryContext divide_int32_int64_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_int32_int64"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_int64_int32_overflow|-9223372036854775808L,-1|overflow + /** + * Divide an int64 value by an int32 value, the result exceeds the range of int64. + * + * Expected Results: + * The query should throw an overflow exception due to int64 overflow. + */ + public QueryContext divide_int64_int32_overflow_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_int64_int32_overflow"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_int32_double|2,1.12d|1.77d + /** + * Divide an int32 value by a double value, the result is within the range of double. + * + * Expected Results: + * The query should return a double type value, identical to the quotient of $1 and $2. + */ + public QueryContext divide_int32_double_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_int32_double"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_float_double|2.0f,1.12d|1.78d + /** + * Divide a float value by a double value, the result is within the range of double. + * + * Expected Results: + * The query should return a double type value, identical to the quotient of $1 and $2. + */ + public QueryContext divide_float_double_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_float_double"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_float_double_NaN|2.0f,0.0d|NaN + /** + * Divide a float value by a double value, where the divisor is zero, resulting in NaN. + * + * Expected Results: + * The query should return NaN as the result of division by zero. + */ + public QueryContext divide_float_double_NaN_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_float_double_NaN"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + } + + public class MultiplyTest { + + // multiply_int32_int32|1,2|2 + /** + * Multiply an int32 value with an int32 value, the result is within the range of int32. + * + * Expected Results: + * The query should return an int32 type value, identical to the product of $1 and $2. + */ + public QueryContext multiply_int32_int32_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 * $2"; + Parameter parameter = queryParameters.get("multiply_int32_int32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // multiply_int32_int32_overflow|2147483647,2|overflow + /** + * Multiply an int32 value with an int32 value, the result exceeds the range of int32. + * + * Expected Results: + * The query should throw an overflow exception due to int32 overflow. + */ + public QueryContext multiply_int32_int32_overflow_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 * $2"; + Parameter parameter = queryParameters.get("multiply_int32_int32_overflow"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // multiply_int32_uint32_int32|1,+2|2 + /** + * Multiply an int32 value with an uint32 value, the result is within the range of int32. + * + * Expected Results: + * The query should return an int32 type value, identical to the product of $1 and $2. + */ + public QueryContext multiply_int32_uint32_int32_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 * $2"; + Parameter parameter = queryParameters.get("multiply_int32_uint32_int32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // multiply_int32_uint32_uint32|4,+1000000000|+4000000000 + /** + * Multiply an int32 value with an uint32 value, the result is out of the range of int32 but within the range of uint32. + * + * Expected Results: + * The query should return a uint32 type value, identical to the product of $1 and $2. + */ + public QueryContext multiply_int32_uint32_uint32_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 * $2"; + Parameter parameter = queryParameters.get("multiply_int32_uint32_uint32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // multiply_int32_uint32_overflow|4,+2000000000|overflow + /** + * Multiply an int32 value with an uint32 value, the result exceeds the range of uint32. + * + * Expected Results: + * The query should throw an overflow exception due to uint32 overflow. + */ + public QueryContext multiply_int32_uint32_overflow_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 * $2"; + Parameter parameter = queryParameters.get("multiply_int32_uint32_overflow"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // multiply_int32_int64|1,2L|2L + /** + * Multiply an int32 value with an int64 value, the result is within the range of int64. + * + * Expected Results: + * The query should return an int64 type value, identical to the product of $1 and $2. + */ + public QueryContext multiply_int32_int64_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 * $2"; + Parameter parameter = queryParameters.get("multiply_int32_int64"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // multiply_int32_int64_overflow|2,9223372036854775807L|overflow + /** + * Multiply an int32 value with an int64 value, the result exceeds the range of int64. + * + * Expected Results: + * The query should throw an overflow exception due to int64 overflow. + */ + public QueryContext multiply_int32_int64_overflow_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 * $2"; + Parameter parameter = queryParameters.get("multiply_int32_int64_overflow"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // multiply_int32_double|2,2.12d|4.24d + /** + * Multiply an int32 value with a double value, the result is within the range of double. + * + * Expected Results: + * The query should return a double type value, identical to the product of $1 and $2. + */ + public QueryContext multiply_int32_double_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 * $2"; + Parameter parameter = queryParameters.get("multiply_int32_double"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // multiply_float_double|2.0f,2.12d|4.24d + /** + * Multiply a float value with a double value, the result is within the range of double. + * + * Expected Results: + * The query should return a double type value, identical to the product of $1 and $2. + */ + public QueryContext multiply_float_double_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 * $2"; + Parameter parameter = queryParameters.get("multiply_float_double"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + } + + public class DivideTest { + + // divide_int32_int32|2,1|2 + /** + * Divide an int32 value by an int32 value, the result is within the range of int32. + * + * Expected Results: + * The query should return an int32 type value, identical to the quotient of $1 and $2. + */ + public QueryContext divide_int32_int32_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_int32_int32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_int32_int32_overflow|-2147483648,-1|overflow + /** + * Divide an int32 value by an int32 value, the result exceeds the range of int32. + * + * Expected Results: + * The query should throw an overflow exception due to int32 overflow. + */ + public QueryContext divide_int32_int32_overflow_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_int32_int32_overflow"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_int32_uint32_int32|2,+1|2 + /** + * Divide an int32 value by an uint32 value, the result is within the range of int32. + * + * Expected Results: + * The query should return an int32 type value, identical to the quotient of $1 and $2. + */ + public QueryContext divide_int32_uint32_int32_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_int32_uint32_int32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_uint32_int32_uint32|+4294967295,1|+4294967295 + /** + * Divide an uint32 value by an int32 value, the result is out of the range of int32 but within the range of uint32. + * + * Expected Results: + * The query should return a uint32 type value, identical to the quotient of $1 and $2. + */ + public QueryContext divide_uint32_int32_uint32_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_uint32_int32_uint32"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_uint32_int32_overflow|+4294967295,-1|overflow + /** + * Divide an uint32 value by a negative int32 value, the result exceeds the range of int32 (INT32_MIN). + * + * Expected Results: + * The query should throw an overflow exception due to int32 overflow. + */ + public QueryContext divide_uint32_int32_overflow_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_uint32_int32_overflow"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_int32_int64|2,1L|2L + /** + * Divide an int32 value by an int64 value, the result is within the range of int64. + * + * Expected Results: + * The query should return an int64 type value, identical to the quotient of $1 and $2. + */ + public QueryContext divide_int32_int64_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_int32_int64"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_int64_int32_overflow|-9223372036854775808L,-1|overflow + /** + * Divide an int64 value by an int32 value, the result exceeds the range of int64. + * + * Expected Results: + * The query should throw an overflow exception due to int64 overflow. + */ + public QueryContext divide_int64_int32_overflow_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_int64_int32_overflow"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_int32_double|2,1.12d|1.77d + /** + * Divide an int32 value by a double value, the result is within the range of double. + * + * Expected Results: + * The query should return a double type value, identical to the quotient of $1 and $2. + */ + public QueryContext divide_int32_double_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_int32_double"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_float_double|2.0f,1.12d|1.78d + /** + * Divide a float value by a double value, the result is within the range of double. + * + * Expected Results: + * The query should return a double type value, identical to the quotient of $1 and $2. + */ + public QueryContext divide_float_double_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_float_double"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + // divide_float_double_NaN|2.0f,0.0d|NaN + /** + * Divide a float value by a double value, where the divisor is zero, resulting in NaN. + * + * Expected Results: + * The query should return NaN as the result of division by zero. + */ + public QueryContext divide_float_double_NaN_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; + Parameter parameter = queryParameters.get("divide_float_double_NaN"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + } + + /** + * Find 'knows' edges between two persons of specific property values. + * + * Expected Results: + * The query should return the property values for the two persons involved in the 'knows' relationship. + * @return + */ + public QueryContext get_knows_between_two_persons_test() { + String query = + "MATCH (p1:person)-[r:knows]->(p2:person)\n" + + " WHERE p1.prop_int32 = $1 AND p2.prop_int32 = $2\n" + + " RETURN p1.prop_int32, p2.prop_int32"; + Parameter parameter = queryParameters.get("get_knows_between_two_persons"); + // render the query, replace the $1 and $2 with the actual values + for (int i = 0; i < parameter.parameters.size(); i++) { + query = query.replace("$" + (i + 1), parameter.parameters.get(i)); + } + return new QueryContext(query, parameter.results); + } +} diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java new file mode 100644 index 000000000000..751e0d86630b --- /dev/null +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java @@ -0,0 +1,113 @@ +/* + * Copyright 2020 Alibaba Group Holding Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.graphscope.cypher.integration.flex.bench; + +import com.alibaba.graphscope.cypher.integration.suite.QueryContext; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.neo4j.driver.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.function.Supplier; + +public class FlexTypeTest { + private static final Logger logger = LoggerFactory.getLogger(FlexTypeTest.class); + private static Session session; + + @BeforeClass + public static void setUp() { + String neo4jServerUrl = + System.getProperty("neo4j.bolt.server.url", "neo4j://localhost:7687"); + session = GraphDatabase.driver(neo4jServerUrl).session(); + } + + @Test + public void run() throws Exception { + FlexTypeQueries queries = new FlexTypeQueries("src/test/resources/flex_bench/parameters"); + + // run comparison test, comparing numeric, string and temporal types + runComponent(queries.getCompare()); + + // run arithmetic plus test + runComponent(queries.getPlus()); + + // run arithmetic minus test + runComponent(queries.getMinus()); + + // run arithmetic multiply test + runComponent(queries.getMultiply()); + + // run arithmetic divide test + runComponent(queries.getDivide()); + } + + private void runComponent(Object component) throws Exception { + Method[] methods = component.getClass().getDeclaredMethods(); + + for (Method method : methods) { + logger.warn(method.getName() + " is running"); + QueryContext ctx = (QueryContext) method.invoke(component); + checkResult(() -> session.run(ctx.getQuery()), ctx); + logger.warn(method.getName() + " is done"); + } + } + + private void checkResult(Supplier resultSupplier, QueryContext ctx) { + List expected = ctx.getExpectedResult(); + if (expected.size() == 1 && expected.get(0).equals("empty")) { + Assert.assertTrue(resultSupplier.get().list().isEmpty()); + } else if (expected.size() == 1 && expected.get(0).equals("overflow")) { + try { + resultSupplier.get().list(); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("overflow")); + } + } else if (expected.size() == 1 && expected.get(0).equals("NaN")) { + try { + resultSupplier.get().list(); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("NaN")); + } + } else { + Record single = resultSupplier.get().list().get(0); + Assert.assertEquals(expected.size(), single.size()); + for (int i = 0; i < expected.size(); i++) { + Value actual = single.get(i); + String expectedValue = expected.get(i); + if (expectedValue.startsWith("+")) { + expectedValue = expectedValue.substring(1); + } + String upperCase = expectedValue.toUpperCase(); + if (upperCase.endsWith("L") || upperCase.endsWith("D") || upperCase.endsWith("F")) { + expectedValue = expectedValue.substring(0, expectedValue.length() - 1); + } + Assert.assertEquals(expectedValue, actual.asString()); + } + } + } + + @AfterClass + public static void tearDown() { + session.close(); + } +} diff --git a/interactive_engine/compiler/src/test/resources/flex_bench/data/knows.csv b/interactive_engine/compiler/src/test/resources/flex_bench/data/knows.csv new file mode 100644 index 000000000000..feef611d8d67 --- /dev/null +++ b/interactive_engine/compiler/src/test/resources/flex_bench/data/knows.csv @@ -0,0 +1,4 @@ +source_person_id,destination_person_id +32,33 +33,34 +32,34 diff --git a/interactive_engine/compiler/src/test/resources/flex_bench/data/person.csv b/interactive_engine/compiler/src/test/resources/flex_bench/data/person.csv new file mode 100644 index 000000000000..2ce1f54db6dc --- /dev/null +++ b/interactive_engine/compiler/src/test/resources/flex_bench/data/person.csv @@ -0,0 +1,6 @@ +prop_int32,prop_uint32,prop_int64,prop_uint64,prop_bool,prop_float,prop_double,prop_text,prop_char,prop_varchar,prop_date,prop_ts +32,12345,1234567890,9876543210,true,3.14,3.14159,Sample text,abcd,abcd,2025-02-12,2025-02-12T12:34:56 +33,12346,1234567891,9876543211,false,2.71,2.71828,Another sample text,efgh,efgh,2025-02-13,2025-02-13T13:45:01 +34,12347,1234567892,9876543212,true,1.62,1.61803,Long text with no truncation,ijkl,ijkl,2025-02-14,2025-02-14T14:56:12 +-2147483648,4294967284,1234567890,18446744073709551602,true,3.14,3.14159,Sample text,abcd,abcd,2025-02-12,2025-02-12T12:34:56 +933,12347,1234567892,9876543212,true,1.62,1.61803,Long text with no truncation,ijkl,ijkl,2025-02-14,2025-02-14T14:56:12 diff --git a/interactive_engine/compiler/src/main/resources/flex_bench/modern.yaml b/interactive_engine/compiler/src/test/resources/flex_bench/modern.yaml similarity index 100% rename from interactive_engine/compiler/src/main/resources/flex_bench/modern.yaml rename to interactive_engine/compiler/src/test/resources/flex_bench/modern.yaml diff --git a/interactive_engine/compiler/src/test/resources/flex_bench/parameters b/interactive_engine/compiler/src/test/resources/flex_bench/parameters new file mode 100644 index 000000000000..5494cc15ce27 --- /dev/null +++ b/interactive_engine/compiler/src/test/resources/flex_bench/parameters @@ -0,0 +1,72 @@ +test_case_name|parameters|results +compare_int32_int32|32|32 +compare_uint32_uint32|+12345|+12345 +compare_uint32_int32|12345|+12345 +// 4294967284 +compare_uint32_int32_overflow|-12|empty +compare_uint64_uint64|+9876543210L|+9876543210L +compare_int64_int64|1234567890L|1234567890L +compare_uint64_int64|9876543210L|+9876543210L +// 18446744073709551602 +compare_uint64_int64_overflow|-14L|empty +compare_int32_int64|32L|32 +// -2147483648 +compare_int32_int64_overflow|2147483648L|empty +compare_float_float|3.14f|3.14f +compare_double_double|3.14159d|3.14159d +compare_float_double|3.14d|3.14f +compare_float_double_loss|3.14159d|empty +compare_int32_double|32.0d|32 +compare_char_text|"abcd"|"abcd" +compare_char_long_text|"abcde"|"abcd" +compare_varchar_long_text|"abcde"|"abcd" +compare_string_long_text|"Long text with no truncation"|"Long text with no truncation" +// 2025-02-13 +compare_date32_i32|20132|20132 +// 2025-02-13T13:45:01 +compare_timestamp_i64|1739454301000L|1739454301000L + +plus_int32_int32|12,13|25 +plus_int32_int32_overflow|2147483647,1|overflow +plus_int32_uint32_int32|12,+13|25 +plus_int32_uint32_uint32|10,+2147483647|+2147483657 +plus_int32_uint32_overflow|1,+4294967295|overflow +plus_int32_int64|12,14L|26L +plus_int32_int64_overflow|10,9223372036854775807L|overflow +plus_int32_double|12,16.23d|28.23d +plus_float_double|12.0f,16.23d|28.23d + +minus_int32_int32|12,13|-1 +minus_int32_int32_overflow|2147483647,-1|overflow +minus_int32_uint32_int32|12,+13|-1 +minus_uint32_int32_uint32|+2147483647,-10|+2147483657 +minus_uint32_int32_overflow|+4294967295,-1|overflow +minus_int32_int64|12,13L|-1L +minus_int64_int32_overflow|9223372036854775807L,-10|overflow +minus_int32_double|12,13.12d|-1.12d +minus_float_double|12.0f,13.12d|-1.12d + +multiply_int32_int32|1,2|2 +multiply_int32_int32_overflow|2147483647,2|overflow +multiply_int32_uint32_int32|1,+2|2 +multiply_int32_uint32_uint32|4,+1000000000|+4000000000 +multiply_int32_uint32_overflow|4,+2000000000|overflow +multiply_int32_int64|1,2L|2L +multiply_int32_int64_overflow|2,9223372036854775807L|overflow +multiply_int32_double|2,2.12d|4.24d +multiply_float_double|2.0f,2.12d|4.24d + +divide_int32_int32|2,1|2 +divide_int32_int32_overflow|-2147483648,-1|overflow +divide_int32_uint32_int32|2,+1|2 +divide_uint32_int32_uint32|+4294967295,1|+4294967295 +divide_uint32_int32_overflow|+4294967295,-1|overflow +divide_int32_int64|2,1L|2L +divide_int64_int32_overflow|-9223372036854775808L,-1|overflow +divide_int32_double|2,1.12d|1.77d +divide_float_double|2.0f,1.12d|1.78d +divide_float_double_NaN|2.0f,0.0d|NaN + +get_knows_between_two_persons|32,33|32,33 + + From 235676ae6ddc96b77871b6d3fedf10f325427a23 Mon Sep 17 00:00:00 2001 From: shirly121 Date: Tue, 18 Feb 2025 13:43:06 +0800 Subject: [PATCH 06/17] minor fix --- .../ir/meta/fetcher/StaticIrMetaFetcher.java | 2 +- .../ir/meta/schema/IrDataTypeConvertor.java | 31 ++++++-- .../integration/flex/bench/FlexTypeTest.java | 71 +++++++++++++++---- .../src/test/resources/flex_bench/parameters | 6 +- 4 files changed, 88 insertions(+), 22 deletions(-) diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/fetcher/StaticIrMetaFetcher.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/fetcher/StaticIrMetaFetcher.java index dae52f6113c8..4c21cefacf86 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/fetcher/StaticIrMetaFetcher.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/fetcher/StaticIrMetaFetcher.java @@ -52,7 +52,7 @@ public StaticIrMetaFetcher(IrMetaReader dataReader, List tracker) this.metaStats = new IrMetaStats( meta.getSnapshotId(), meta.getSchema(), meta.getStoredProcedures(), stats); - if (tracker != null && stats != null) { + if (tracker != null) { tracker.forEach(t -> t.onStatsChanged(this.metaStats)); } } diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/IrDataTypeConvertor.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/IrDataTypeConvertor.java index d71a546b39be..72dc8f6168ef 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/IrDataTypeConvertor.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/IrDataTypeConvertor.java @@ -45,6 +45,11 @@ public interface IrDataTypeConvertor { Logger logger = LoggerFactory.getLogger(IrDataTypeConvertor.class); + int UINT32_PRECISION = 10; + int UINT32_SCALE = 0; + int UINT64_PRECISION = 20; + int UINT64_SCALE = 0; + RelDataType convert(T dataFrom); T convert(RelDataType dataFrom); @@ -220,9 +225,15 @@ public RelDataType convert(GSDataTypeDesc from) { case "DT_ANY": // any type return typeFactory.createSqlType(SqlTypeName.ANY); + case "DT_UNSIGNED_INT32": + return typeFactory.createSqlType( + SqlTypeName.DECIMAL, UINT32_PRECISION, UINT32_SCALE); case "DT_SIGNED_INT32": // 4-bytes signed integer return typeFactory.createSqlType(SqlTypeName.INTEGER); + case "DT_UNSIGNED_INT64": + return typeFactory.createSqlType( + SqlTypeName.DECIMAL, UINT64_PRECISION, UINT64_SCALE); case "DT_SIGNED_INT64": // 8-bytes signed integer return typeFactory.createSqlType(SqlTypeName.BIGINT); @@ -435,12 +446,20 @@ public GSDataTypeDesc convert(RelDataType from) { ImmutableMap.of("key_type", keyType, "value_type", valueType)); break; case DECIMAL: - yamlDesc = - ImmutableMap.of( - "decimal", - ImmutableMap.of( - "precision", from.getPrecision(), - "scale", from.getScale())); + if (from.getPrecision() == UINT32_PRECISION + && from.getScale() == UINT32_SCALE) { + yamlDesc = ImmutableMap.of("primitive_type", "DT_UNSIGNED_INT32"); + } else if (from.getPrecision() == UINT64_PRECISION + && from.getScale() == UINT64_SCALE) { + yamlDesc = ImmutableMap.of("primitive_type", "DT_UNSIGNED_INT64"); + } else { + yamlDesc = + ImmutableMap.of( + "decimal", + ImmutableMap.of( + "precision", from.getPrecision(), + "scale", from.getScale())); + } break; default: if (throwsOnFail) { diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java index 751e0d86630b..bfc60c6ba74a 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java @@ -18,6 +18,7 @@ import com.alibaba.graphscope.cypher.integration.suite.QueryContext; +import org.javatuples.Pair; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; @@ -34,8 +35,13 @@ public class FlexTypeTest { private static final Logger logger = LoggerFactory.getLogger(FlexTypeTest.class); private static Session session; + /** + * start compiler before the test: + * make run graph.schema=./src/test/resources/flex_bench/modern.yaml graph.planner.opt=CBO graph.physical.opt=proto + */ @BeforeClass public static void setUp() { + String neo4jServerUrl = System.getProperty("neo4j.bolt.server.url", "neo4j://localhost:7687"); session = GraphDatabase.driver(neo4jServerUrl).session(); @@ -46,30 +52,67 @@ public void run() throws Exception { FlexTypeQueries queries = new FlexTypeQueries("src/test/resources/flex_bench/parameters"); // run comparison test, comparing numeric, string and temporal types - runComponent(queries.getCompare()); + Pair compare = runComponent(queries.getCompare()); // run arithmetic plus test - runComponent(queries.getPlus()); + Pair plus = runComponent(queries.getPlus()); // run arithmetic minus test - runComponent(queries.getMinus()); + Pair minus = runComponent(queries.getMinus()); // run arithmetic multiply test - runComponent(queries.getMultiply()); + Pair multi = runComponent(queries.getMultiply()); // run arithmetic divide test - runComponent(queries.getDivide()); + Pair divide = runComponent(queries.getDivide()); + + logger.warn( + "\n component: Compare, total tests {}, passed tests {}" + + "\n component: Plus, total tests {}, passed tests {}" + + "\n component: Minus, total tests {}, passed tests {}" + + "\n component: Multiply, total tests {}, passed tests {}" + + "\n component: Divide, total tests {}, passed tests {}", + compare.getValue0(), + compare.getValue1(), + plus.getValue0(), + plus.getValue1(), + minus.getValue0(), + minus.getValue1(), + multi.getValue0(), + multi.getValue1(), + divide.getValue0(), + divide.getValue1()); + + int total = + compare.getValue0() + + plus.getValue0() + + minus.getValue0() + + multi.getValue0() + + divide.getValue0(); + int passed = + compare.getValue1() + + plus.getValue1() + + minus.getValue1() + + multi.getValue1() + + divide.getValue1(); + Assert.assertEquals("total tests: " + total + ", passed tests: " + passed, total, passed); } - private void runComponent(Object component) throws Exception { + private Pair runComponent(Object component) { Method[] methods = component.getClass().getDeclaredMethods(); - + int totalTests = methods.length; + int passTests = 0; for (Method method : methods) { - logger.warn(method.getName() + " is running"); - QueryContext ctx = (QueryContext) method.invoke(component); - checkResult(() -> session.run(ctx.getQuery()), ctx); - logger.warn(method.getName() + " is done"); + try { + QueryContext ctx = (QueryContext) method.invoke(component); + checkResult(() -> session.run(ctx.getQuery()), ctx); + logger.warn("test {} passed.", method.getName()); + ++passTests; + } catch (Throwable t) { + logger.error("test {} failed.", method.getName(), t); + } } + return Pair.with(totalTests, passTests); } private void checkResult(Supplier resultSupplier, QueryContext ctx) { @@ -79,17 +122,21 @@ private void checkResult(Supplier resultSupplier, QueryContext ctx) { } else if (expected.size() == 1 && expected.get(0).equals("overflow")) { try { resultSupplier.get().list(); + Assert.fail("overflow exception should have been thrown"); } catch (Exception e) { Assert.assertTrue(e.getMessage().contains("overflow")); } } else if (expected.size() == 1 && expected.get(0).equals("NaN")) { try { resultSupplier.get().list(); + Assert.fail("NaN exception should have been thrown"); } catch (Exception e) { Assert.assertTrue(e.getMessage().contains("NaN")); } } else { - Record single = resultSupplier.get().list().get(0); + List records = resultSupplier.get().list(); + Assert.assertEquals(1, records.size()); + Record single = records.get(0); Assert.assertEquals(expected.size(), single.size()); for (int i = 0; i < expected.size(); i++) { Value actual = single.get(i); diff --git a/interactive_engine/compiler/src/test/resources/flex_bench/parameters b/interactive_engine/compiler/src/test/resources/flex_bench/parameters index 5494cc15ce27..0caa4c50f4ce 100644 --- a/interactive_engine/compiler/src/test/resources/flex_bench/parameters +++ b/interactive_engine/compiler/src/test/resources/flex_bench/parameters @@ -1,10 +1,10 @@ test_case_name|parameters|results -compare_int32_int32|32|32 -compare_uint32_uint32|+12345|+12345 +compare_int32_int32|-2147483648|-2147483648 +compare_uint32_uint32|+4294967284|+4294967284 compare_uint32_int32|12345|+12345 // 4294967284 compare_uint32_int32_overflow|-12|empty -compare_uint64_uint64|+9876543210L|+9876543210L +compare_uint64_uint64|+18446744073709551602L|+18446744073709551602L compare_int64_int64|1234567890L|1234567890L compare_uint64_int64|9876543210L|+9876543210L // 18446744073709551602 From f1d0e7c5589b39d6e53744e12ece6bca0fda09ef Mon Sep 17 00:00:00 2001 From: shirly121 Date: Tue, 18 Feb 2025 14:15:46 +0800 Subject: [PATCH 07/17] fix bugs of type conversion of uint64 --- .../ir/meta/schema/IrDataTypeConvertor.java | 1 + .../common/ir/type/GraphTypeFactoryImpl.java | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/IrDataTypeConvertor.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/IrDataTypeConvertor.java index 72dc8f6168ef..632ebe8610cf 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/IrDataTypeConvertor.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/IrDataTypeConvertor.java @@ -45,6 +45,7 @@ public interface IrDataTypeConvertor { Logger logger = LoggerFactory.getLogger(IrDataTypeConvertor.class); + // support unsigned type as decimal type with fixed precision and scale int UINT32_PRECISION = 10; int UINT32_SCALE = 0; int UINT64_PRECISION = 20; diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/type/GraphTypeFactoryImpl.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/type/GraphTypeFactoryImpl.java index 881e8a6837fa..1985cd23d949 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/type/GraphTypeFactoryImpl.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/type/GraphTypeFactoryImpl.java @@ -18,12 +18,16 @@ import com.alibaba.graphscope.common.config.Configs; import com.alibaba.graphscope.common.config.FrontendConfig; +import com.alibaba.graphscope.common.ir.meta.schema.IrDataTypeConvertor; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.apache.calcite.jdbc.JavaTypeFactoryImpl; import org.apache.calcite.rel.type.*; import org.apache.calcite.rex.RexNode; +import org.apache.calcite.sql.type.BasicSqlType; +import org.apache.calcite.sql.type.SqlTypeName; +import org.apache.calcite.sql.type.SqlTypeUtil; import org.apache.calcite.util.Util; import org.checkerframework.checker.nullness.qual.Nullable; @@ -190,4 +194,16 @@ public RelDataType createArbitraryMapType( } return createArbitraryMapType(leastKeyValueType, isNullable); } + + @Override + public RelDataType createSqlType(SqlTypeName typeName, int precision, int scale) { + if (typeName == SqlTypeName.DECIMAL + && precision == IrDataTypeConvertor.UINT64_PRECISION + && scale == IrDataTypeConvertor.UINT64_SCALE) { + RelDataType newType = new BasicSqlType(this.typeSystem, typeName, precision, scale); + newType = SqlTypeUtil.addCharsetAndCollation(newType, this); + return this.canonize(newType); + } + return super.createSqlType(typeName, precision, scale); + } } From 6438aa6009af17cc777d523d0cb08358104b2b27 Mon Sep 17 00:00:00 2001 From: shirly121 Date: Wed, 19 Feb 2025 13:50:06 +0800 Subject: [PATCH 08/17] support u32 and u64 types in compiler --- interactive_engine/compiler/Makefile | 2 + interactive_engine/compiler/pom.xml | 1 + .../common/config/FrontendConfig.java | 3 + .../ir/meta/schema/IrDataTypeConvertor.java | 4 + .../common/ir/runtime/proto/Utils.java | 20 ++ .../common/ir/tools/GraphBuilder.java | 16 +- .../common/ir/type/GraphTypeFactoryImpl.java | 69 +++++- .../antlr4/visitor/ExpressionVisitor.java | 33 +++ .../cypher/antlr4/visitor/LiteralVisitor.java | 3 + .../cypher/result/CypherRecordParser.java | 11 + .../graphscope/cypher/antlr4/TypeTest.java | 143 ++++++++++++ .../graphscope/cypher/antlr4/Utils.java | 10 + .../integration/flex/bench/FlexTypeTest.java | 27 ++- .../proto/compare_double_float_test.json | 216 ++++++++++++++++++ .../proto/compare_uint64_uint64_test.json | 216 ++++++++++++++++++ .../proto/divide_int32_uint32_int32.json | 183 +++++++++++++++ .../executor/ir/proto/common.proto | 3 + 17 files changed, 947 insertions(+), 13 deletions(-) create mode 100644 interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/TypeTest.java create mode 100644 interactive_engine/compiler/src/test/resources/proto/compare_double_float_test.json create mode 100644 interactive_engine/compiler/src/test/resources/proto/compare_uint64_uint64_test.json create mode 100644 interactive_engine/compiler/src/test/resources/proto/divide_int32_uint32_int32.json diff --git a/interactive_engine/compiler/Makefile b/interactive_engine/compiler/Makefile index b1a12978074d..fea6a06948c3 100644 --- a/interactive_engine/compiler/Makefile +++ b/interactive_engine/compiler/Makefile @@ -25,6 +25,7 @@ physical:= procedure:= extra:= config.path:=conf/ir.compiler.properties +disable.expr.simplify:= build: cd $(CUR_DIR)/.. && \ @@ -63,6 +64,7 @@ run: -Dgraph.planner.rules=${graph.planner.rules} \ -Dgraph.planner.opt=${graph.planner.opt} \ -Dgraph.statistics=${graph.statistics} \ + -Ddisable.expr.simplify={disable.expr.simplify} \ com.alibaba.graphscope.GraphServer ${config.path} # make physical_plan config.path='' diff --git a/interactive_engine/compiler/pom.xml b/interactive_engine/compiler/pom.xml index 6392385974b2..dea48d62116d 100644 --- a/interactive_engine/compiler/pom.xml +++ b/interactive_engine/compiler/pom.xml @@ -362,6 +362,7 @@ **/IrPatternTest.java **/MovieTest.java **/GraphAlgoTest.java + **/FlexTypeTest.java diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/config/FrontendConfig.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/config/FrontendConfig.java index bbbbe19b7967..b01338db3b01 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/config/FrontendConfig.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/config/FrontendConfig.java @@ -66,4 +66,7 @@ public class FrontendConfig { public static final Config METRICS_TOOL_INTERVAL_MS = Config.longConfig("metrics.tool.interval.ms", 5 * 60 * 1000L); + + public static final Config DISABLE_EXPR_SIMPLIFY = + Config.boolConfig("disable.expr.simplify", false); } diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/IrDataTypeConvertor.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/IrDataTypeConvertor.java index 632ebe8610cf..aa98ac90167b 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/IrDataTypeConvertor.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/IrDataTypeConvertor.java @@ -36,6 +36,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.math.BigDecimal; import java.util.Map; import java.util.Objects; @@ -51,6 +52,9 @@ public interface IrDataTypeConvertor { int UINT64_PRECISION = 20; int UINT64_SCALE = 0; + BigDecimal UINT32_MAX = new BigDecimal("4294967295"); + BigDecimal UINT64_MAX = new BigDecimal("18446744073709551615"); + RelDataType convert(T dataFrom); T convert(RelDataType dataFrom); diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/Utils.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/Utils.java index 317cbfcadb4d..79574fd57555 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/Utils.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/Utils.java @@ -46,6 +46,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; @@ -113,7 +114,26 @@ public static final Common.Value protoValue(RexLiteral literal) { : (String) literal.getValue(); return Common.Value.newBuilder().setStr(valueStr).build(); case DECIMAL: + if (literal.getType().getPrecision() == IrDataTypeConvertor.UINT32_PRECISION + && literal.getType().getScale() == IrDataTypeConvertor.UINT32_SCALE) { + BigDecimal uint32Value = (BigDecimal) literal.getValue(); + return Common.Value.newBuilder().setU32(uint32Value.intValue()).build(); + } + if (literal.getType().getPrecision() == IrDataTypeConvertor.UINT64_PRECISION + && literal.getType().getScale() == IrDataTypeConvertor.UINT64_SCALE) { + BigDecimal uint32Value = (BigDecimal) literal.getValue(); + return Common.Value.newBuilder().setU64(uint32Value.longValue()).build(); + } + throw new UnsupportedOperationException( + "decimal type with precision=" + + literal.getType().getPrecision() + + ", scale=" + + literal.getType().getScale() + + " is unsupported yet"); case FLOAT: + return Common.Value.newBuilder() + .setF32(((Number) literal.getValue()).floatValue()) + .build(); case DOUBLE: return Common.Value.newBuilder() .setF64(((Number) literal.getValue()).doubleValue()) diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/GraphBuilder.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/GraphBuilder.java index b1ff07686c5f..ff4c03df037e 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/GraphBuilder.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/GraphBuilder.java @@ -42,6 +42,7 @@ import com.alibaba.graphscope.common.ir.type.*; import com.alibaba.graphscope.gremlin.Utils; import com.alibaba.graphscope.proto.frontend.Code; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -96,6 +97,9 @@ protected GraphBuilder(Context context, GraphOptCluster cluster, RelOptSchema re new GraphRexSimplify( cluster.getRexBuilder(), RelOptPredicateList.EMPTY, RexUtil.EXECUTOR)); this.configs = context.unwrapOrThrow(Configs.class); + if (FrontendConfig.DISABLE_EXPR_SIMPLIFY.get(this.configs)) { + disableSimplify(); + } } /** @@ -109,6 +113,12 @@ public static GraphBuilder create( return new GraphBuilder(context, cluster, relOptSchema); } + @VisibleForTesting + public void disableSimplify() { + Config config = Utils.getFieldValue(RelBuilder.class, this, "config"); + config.withSimplify(false); + } + public Context getContext() { return this.configs; } @@ -1739,7 +1749,11 @@ public RexLiteral literal(@Nullable Object value) { return rexBuilder.makeLiteral((Boolean) value); } else if (value instanceof BigDecimal) { return rexBuilder.makeExactLiteral((BigDecimal) value); - } else if (value instanceof Float || value instanceof Double) { + } else if (value instanceof Float) { + return rexBuilder.makeApproxLiteral( + BigDecimal.valueOf(((Number) value).floatValue()), + getTypeFactory().createSqlType(SqlTypeName.FLOAT)); + } else if (value instanceof Double) { return rexBuilder.makeApproxLiteral(BigDecimal.valueOf(((Number) value).doubleValue())); } else if (value instanceof Long) { // convert long to BIGINT, i.e. 2l return rexBuilder.makeBigintLiteral(BigDecimal.valueOf(((Number) value).longValue())); diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/type/GraphTypeFactoryImpl.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/type/GraphTypeFactoryImpl.java index 1985cd23d949..a7516fd5cb0c 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/type/GraphTypeFactoryImpl.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/type/GraphTypeFactoryImpl.java @@ -25,7 +25,6 @@ import org.apache.calcite.jdbc.JavaTypeFactoryImpl; import org.apache.calcite.rel.type.*; import org.apache.calcite.rex.RexNode; -import org.apache.calcite.sql.type.BasicSqlType; import org.apache.calcite.sql.type.SqlTypeName; import org.apache.calcite.sql.type.SqlTypeUtil; import org.apache.calcite.util.Util; @@ -40,7 +39,65 @@ public class GraphTypeFactoryImpl extends JavaTypeFactoryImpl { private final Configs configs; public GraphTypeFactoryImpl(Configs configs) { - super(); + super( + new RelDataTypeSystemImpl() { + @Override + public int getMaxNumericPrecision() { + return 20; + } + + @Override + public @Nullable RelDataType deriveDecimalPlusType( + RelDataTypeFactory typeFactory, RelDataType type1, RelDataType type2) { + if (!SqlTypeUtil.isExactNumeric(type1) + || !SqlTypeUtil.isExactNumeric(type2) + || !isDecimal(type1) && !isDecimal(type2)) { + return null; + } + return super.deriveDecimalPlusType(typeFactory, type1, type2); + } + + @Override + public @Nullable RelDataType deriveDecimalMultiplyType( + RelDataTypeFactory typeFactory, RelDataType type1, RelDataType type2) { + if (!SqlTypeUtil.isExactNumeric(type1) + || !SqlTypeUtil.isExactNumeric(type2) + || !isDecimal(type1) && !isDecimal(type2)) { + return null; + } + return super.deriveDecimalMultiplyType(typeFactory, type1, type2); + } + + @Override + public @Nullable RelDataType deriveDecimalDivideType( + RelDataTypeFactory typeFactory, RelDataType type1, RelDataType type2) { + if (!SqlTypeUtil.isExactNumeric(type1) + || !SqlTypeUtil.isExactNumeric(type2) + || !isDecimal(type1) && !isDecimal(type2)) { + return null; + } + return super.deriveDecimalDivideType(typeFactory, type1, type2); + } + + private boolean isDecimal(RelDataType type) { + SqlTypeName typeName = type.getSqlTypeName(); + return typeName == SqlTypeName.DECIMAL + && !isUint32(type) + && !isUint64(type); + } + + private boolean isUint32(RelDataType type) { + return type.getSqlTypeName() == SqlTypeName.DECIMAL + && type.getPrecision() == IrDataTypeConvertor.UINT32_PRECISION + && type.getScale() == IrDataTypeConvertor.UINT32_SCALE; + } + + private boolean isUint64(RelDataType type) { + return type.getSqlTypeName() == SqlTypeName.DECIMAL + && type.getPrecision() == IrDataTypeConvertor.UINT64_PRECISION + && type.getScale() == IrDataTypeConvertor.UINT64_SCALE; + } + }); this.configs = configs; } @@ -198,11 +255,9 @@ public RelDataType createArbitraryMapType( @Override public RelDataType createSqlType(SqlTypeName typeName, int precision, int scale) { if (typeName == SqlTypeName.DECIMAL - && precision == IrDataTypeConvertor.UINT64_PRECISION - && scale == IrDataTypeConvertor.UINT64_SCALE) { - RelDataType newType = new BasicSqlType(this.typeSystem, typeName, precision, scale); - newType = SqlTypeUtil.addCharsetAndCollation(newType, this); - return this.canonize(newType); + && precision == typeSystem.getDefaultPrecision(SqlTypeName.BIGINT) + && scale == 0) { + return createSqlType(SqlTypeName.BIGINT); } return super.createSqlType(typeName, precision, scale); } diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/ExpressionVisitor.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/ExpressionVisitor.java index 70bc21515fd6..72518e44a860 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/ExpressionVisitor.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/ExpressionVisitor.java @@ -20,6 +20,7 @@ import com.alibaba.graphscope.common.antlr4.ExprVisitorResult; import com.alibaba.graphscope.common.config.Configs; import com.alibaba.graphscope.common.ir.meta.function.GraphFunctions; +import com.alibaba.graphscope.common.ir.meta.schema.IrDataTypeConvertor; import com.alibaba.graphscope.common.ir.rel.type.group.GraphAggCall; import com.alibaba.graphscope.common.ir.rex.RexGraphVariable; import com.alibaba.graphscope.common.ir.rex.RexTmpVariable; @@ -38,15 +39,18 @@ import org.antlr.v4.runtime.tree.TerminalNode; import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.type.RelDataType; import org.apache.calcite.rex.*; import org.apache.calcite.sql.SqlKind; import org.apache.calcite.sql.SqlOperator; import org.apache.calcite.sql.type.SqlTypeFamily; +import org.apache.calcite.sql.type.SqlTypeName; import org.apache.calcite.tools.RelBuilder; import org.apache.calcite.util.NlsString; import org.apache.commons.lang3.ObjectUtils; import org.checkerframework.checker.nullness.qual.Nullable; +import java.math.BigDecimal; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -220,6 +224,35 @@ public ExprVisitorResult visitOC_MultiplyDivideModuloExpression( @Override public ExprVisitorResult visitOC_UnaryAddOrSubtractExpression( CypherGSParser.OC_UnaryAddOrSubtractExpressionContext ctx) { + String text = ctx.getText().toLowerCase(); + // convert unary add to unsigned integer + if (text.startsWith("+")) { + String value = text.substring(1); + if (text.endsWith("l")) { + value = value.substring(0, value.length() - 1); + } + BigDecimal decimal = new BigDecimal(value); + RelDataType type; + if (decimal.compareTo(IrDataTypeConvertor.UINT32_MAX) <= 0 && !text.endsWith("l")) { + type = + builder.getTypeFactory() + .createSqlType( + SqlTypeName.DECIMAL, + IrDataTypeConvertor.UINT32_PRECISION, + IrDataTypeConvertor.UINT32_SCALE); + } else if (decimal.compareTo(IrDataTypeConvertor.UINT64_MAX) <= 0) { + type = + builder.getTypeFactory() + .createSqlType( + SqlTypeName.DECIMAL, + IrDataTypeConvertor.UINT64_PRECISION, + IrDataTypeConvertor.UINT64_SCALE); + } else { + throw new IllegalArgumentException( + "value: " + decimal + " exceeds the range of uint64"); + } + return new ExprVisitorResult(builder.getRexBuilder().makeLiteral(decimal, type)); + } ExprVisitorResult operand = visitOC_ListOperatorExpression(ctx.oC_ListOperatorExpression()); List operators = Utils.getOperators(ctx.children, ImmutableList.of("-", "+"), true); diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/LiteralVisitor.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/LiteralVisitor.java index 346fa16e78ed..c131af45f7c7 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/LiteralVisitor.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/LiteralVisitor.java @@ -84,6 +84,9 @@ public Object visitOC_IntegerLiteral(CypherGSParser.OC_IntegerLiteralContext ctx @Override public Object visitOC_DoubleLiteral(CypherGSParser.OC_DoubleLiteralContext ctx) { String floatLiteral = ctx.getText().toLowerCase(); + if (floatLiteral.endsWith("f")) { + return Float.valueOf(floatLiteral); + } return Double.valueOf(floatLiteral); } diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/result/CypherRecordParser.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/result/CypherRecordParser.java index fb3f083aedc9..d5752d2a652a 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/result/CypherRecordParser.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/result/CypherRecordParser.java @@ -303,6 +303,17 @@ protected AnyValue parseValue(Common.Value value, @Nullable RelDataType dataType return Values.intValue(value.getI32()); case I64: return Values.longValue(value.getI64()); + case U32: + // cypher does not support u32 directly, represent u32 as long, which is enough to + // hold u32 value. + return Values.longValue(value.getU32()); + case U64: + // cypher does not support u64 directly, represent u64 as long, + // user need to convert long to u64 and handle the overflow cases at the + // client-side. + return Values.longValue(value.getU64()); + case F32: + return Values.floatValue(value.getF32()); case F64: return Values.doubleValue(value.getF64()); case STR: diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/TypeTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/TypeTest.java new file mode 100644 index 000000000000..73e2ba1dbc95 --- /dev/null +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/TypeTest.java @@ -0,0 +1,143 @@ +/* + * Copyright 2020 Alibaba Group Holding Limited. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.graphscope.cypher.antlr4; + +import com.alibaba.graphscope.common.config.Configs; +import com.alibaba.graphscope.common.ir.meta.IrMeta; +import com.alibaba.graphscope.common.ir.planner.GraphIOProcessor; +import com.alibaba.graphscope.common.ir.planner.GraphRelOptimizer; +import com.alibaba.graphscope.common.ir.runtime.proto.GraphRelProtoPhysicalBuilder; +import com.alibaba.graphscope.common.ir.tools.GraphBuilder; +import com.alibaba.graphscope.common.ir.tools.LogicalPlan; +import com.alibaba.graphscope.common.utils.FileUtils; +import com.google.common.collect.ImmutableMap; + +import org.apache.calcite.rel.RelNode; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.math.BigDecimal; +import java.math.BigInteger; + +public class TypeTest { + private static Configs configs; + private static IrMeta irMeta; + private static GraphRelOptimizer optimizer; + + @BeforeClass + public static void beforeClass() { + configs = + new Configs( + ImmutableMap.of( + "graph.planner.is.on", + "true", + "graph.planner.opt", + "CBO", + "graph.planner.rules", + "FilterIntoJoinRule, FilterMatchRule, ExtendIntersectRule," + + " ExpandGetVFusionRule")); + optimizer = new GraphRelOptimizer(configs); + irMeta = + com.alibaba.graphscope.common.ir.Utils.mockIrMeta( + "flex_bench/modern.yaml", "", optimizer); + } + + @Test + public void compare_uint64_uint64_test() { + GraphBuilder builder = + com.alibaba.graphscope.common.ir.Utils.mockGraphBuilder(optimizer, irMeta); + RelNode before = + com.alibaba.graphscope.cypher.antlr4.Utils.eval( + "MATCH (p:person)\n" + + " WHERE p.prop_uint64 = +18446744073709551602L\n" + + " RETURN p.prop_uint64", + builder) + .build(); + RelNode after = optimizer.optimize(before, new GraphIOProcessor(builder, irMeta)); + GraphRelProtoPhysicalBuilder builder1 = + new GraphRelProtoPhysicalBuilder(configs, irMeta, new LogicalPlan(after)); + Assert.assertEquals( + FileUtils.readJsonFromResource("proto/compare_uint64_uint64_test.json"), + builder1.build().explain().trim()); + } + + @Test + public void compare_double_float_test() { + GraphBuilder builder = + com.alibaba.graphscope.common.ir.Utils.mockGraphBuilder(optimizer, irMeta); + RelNode before = + com.alibaba.graphscope.cypher.antlr4.Utils.eval( + "MATCH (p:person)\n" + + " WHERE p.prop_double = 1.2f\n" + + " RETURN p.prop_double", + builder) + .build(); + RelNode after = optimizer.optimize(before, new GraphIOProcessor(builder, irMeta)); + GraphRelProtoPhysicalBuilder builder1 = + new GraphRelProtoPhysicalBuilder(configs, irMeta, new LogicalPlan(after)); + Assert.assertEquals( + FileUtils.readJsonFromResource("proto/compare_double_float_test.json"), + builder1.build().explain().trim()); + } + + @Test + public void convert_int32_to_uint32_test() { + BigDecimal expected = new BigDecimal("4294967284"); + long signedVal = expected.longValue(); + BigDecimal unsignedVal = new BigDecimal(new BigInteger(1, Utils.longToBytes(signedVal))); + Assert.assertEquals(expected, unsignedVal); + } + + @Test + public void convert_int64_to_uint64_test() { + BigDecimal expected = new BigDecimal("18446744073709551602"); + long signedVal = expected.longValue(); + BigDecimal unsignedVal = new BigDecimal(new BigInteger(1, Utils.longToBytes(signedVal))); + Assert.assertEquals(expected, unsignedVal); + } + + /** + * When plus/minus/multiply/divide an int32 value with an uint32 value, the expected result range should be [INT32_MIN, UINT32_MAX], + * but there is not a type that can represent this range, currently we use uint32 instead. + * + * The return type is the least restrictive type of two parameters, specifically: + * + * uint32, uint32 -> uint32 + * uint32, int32 -> uint32 + * uint32, uint64 -> uint64 + * uint32, int64 -> int64 + * int32, int64 -> int64 + * int32, uint64 -> uint64 + */ + @Test + public void divide_int32_uint64_test() { + GraphBuilder builder = + com.alibaba.graphscope.common.ir.Utils.mockGraphBuilder(optimizer, irMeta); + builder.disableSimplify(); + RelNode before = + com.alibaba.graphscope.cypher.antlr4.Utils.eval( + "MATCH (p:person) RETURN 2 / +3L", builder) + .build(); + RelNode after = optimizer.optimize(before, new GraphIOProcessor(builder, irMeta)); + GraphRelProtoPhysicalBuilder builder1 = + new GraphRelProtoPhysicalBuilder(configs, irMeta, new LogicalPlan(after)); + Assert.assertEquals( + FileUtils.readJsonFromResource("proto/divide_int32_uint32_int32.json"), + builder1.build().explain().trim()); + } +} diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/Utils.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/Utils.java index 01f5d916d97a..36bd72b25e4b 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/Utils.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/Utils.java @@ -23,6 +23,9 @@ import com.alibaba.graphscope.cypher.antlr4.visitor.GraphBuilderVisitor; import com.alibaba.graphscope.cypher.antlr4.visitor.LogicalPlanVisitor; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + public abstract class Utils { public static final GraphBuilder eval(String query) { GraphBuilder graphBuilder = com.alibaba.graphscope.common.ir.Utils.mockGraphBuilder(); @@ -48,4 +51,11 @@ public static LogicalPlan evalLogicalPlan(String query, String schemaPath) { LogicalPlanVisitor logicalPlanVisitor = new LogicalPlanVisitor(graphBuilder, irMeta); return logicalPlanVisitor.visit(new CypherAntlr4Parser().parse(query)); } + + public static byte[] longToBytes(long value) { + ByteBuffer buffer = ByteBuffer.allocate(8); + buffer.order(ByteOrder.BIG_ENDIAN); + buffer.putLong(value); + return buffer.array(); + } } diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java index bfc60c6ba74a..2e5b642aa63b 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java @@ -16,6 +16,7 @@ package com.alibaba.graphscope.cypher.integration.flex.bench; +import com.alibaba.graphscope.cypher.antlr4.Utils; import com.alibaba.graphscope.cypher.integration.suite.QueryContext; import org.javatuples.Pair; @@ -28,6 +29,8 @@ import org.slf4j.LoggerFactory; import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.math.BigInteger; import java.util.List; import java.util.function.Supplier; @@ -37,11 +40,10 @@ public class FlexTypeTest { /** * start compiler before the test: - * make run graph.schema=./src/test/resources/flex_bench/modern.yaml graph.planner.opt=CBO graph.physical.opt=proto + * make run graph.schema=./src/test/resources/flex_bench/modern.yaml graph.planner.opt=CBO graph.physical.opt=proto disable.expr.simplify=true */ @BeforeClass public static void setUp() { - String neo4jServerUrl = System.getProperty("neo4j.bolt.server.url", "neo4j://localhost:7687"); session = GraphDatabase.driver(neo4jServerUrl).session(); @@ -124,14 +126,18 @@ private void checkResult(Supplier resultSupplier, QueryContext ctx) { resultSupplier.get().list(); Assert.fail("overflow exception should have been thrown"); } catch (Exception e) { - Assert.assertTrue(e.getMessage().contains("overflow")); + Assert.assertTrue( + "cannot catch overflow exception from execution message", + e.getMessage().contains("overflow")); } } else if (expected.size() == 1 && expected.get(0).equals("NaN")) { try { resultSupplier.get().list(); Assert.fail("NaN exception should have been thrown"); } catch (Exception e) { - Assert.assertTrue(e.getMessage().contains("NaN")); + Assert.assertTrue( + "cannot catch NaN exception from execution message", + e.getMessage().contains("NaN")); } } else { List records = resultSupplier.get().list(); @@ -141,14 +147,17 @@ private void checkResult(Supplier resultSupplier, QueryContext ctx) { for (int i = 0; i < expected.size(); i++) { Value actual = single.get(i); String expectedValue = expected.get(i); + boolean unsigned = false; if (expectedValue.startsWith("+")) { expectedValue = expectedValue.substring(1); + unsigned = true; } String upperCase = expectedValue.toUpperCase(); if (upperCase.endsWith("L") || upperCase.endsWith("D") || upperCase.endsWith("F")) { expectedValue = expectedValue.substring(0, expectedValue.length() - 1); } - Assert.assertEquals(expectedValue, actual.asString()); + String actualValue = getActualValue(actual, unsigned); + Assert.assertEquals(expectedValue, actualValue); } } } @@ -157,4 +166,12 @@ private void checkResult(Supplier resultSupplier, QueryContext ctx) { public static void tearDown() { session.close(); } + + public String getActualValue(Value actual, boolean unsigned) { + if (unsigned) { + long value = actual.asLong(); + return new BigDecimal(new BigInteger(1, Utils.longToBytes(value))).toString(); + } + return actual.toString(); + } } diff --git a/interactive_engine/compiler/src/test/resources/proto/compare_double_float_test.json b/interactive_engine/compiler/src/test/resources/proto/compare_double_float_test.json new file mode 100644 index 000000000000..7c37de4adc25 --- /dev/null +++ b/interactive_engine/compiler/src/test/resources/proto/compare_double_float_test.json @@ -0,0 +1,216 @@ +{ + "plan": [{ + "opr": { + "scan": { + "alias": 0, + "params": { + "tables": [{ + "id": 0 + }], + "predicate": { + "operators": [{ + "var": { + "property": { + "key": { + "name": "prop_double" + } + }, + "nodeType": { + "dataType": { + "primitiveType": "DT_DOUBLE" + } + } + }, + "nodeType": { + "dataType": { + "primitiveType": "DT_DOUBLE" + } + } + }, { + "logical": "EQ", + "nodeType": { + "dataType": { + "primitiveType": "DT_BOOL" + } + } + }, { + "const": { + "f32": 1.2 + }, + "nodeType": { + "dataType": { + "primitiveType": "DT_FLOAT" + } + } + }] + }, + "sampleRatio": 1.0 + } + } + }, + "metaData": [{ + "type": { + "graphType": { + "graphDataType": [{ + "label": { + }, + "props": [{ + "propId": { + "name": "prop_int32" + }, + "type": { + "primitiveType": "DT_SIGNED_INT32" + } + }, { + "propId": { + "name": "prop_uint32" + }, + "type": { + "primitiveType": "DT_UNSIGNED_INT32" + } + }, { + "propId": { + "name": "prop_int64" + }, + "type": { + "primitiveType": "DT_SIGNED_INT64" + } + }, { + "propId": { + "name": "prop_uint64" + }, + "type": { + "primitiveType": "DT_UNSIGNED_INT64" + } + }, { + "propId": { + "name": "prop_bool" + }, + "type": { + "primitiveType": "DT_BOOL" + } + }, { + "propId": { + "name": "prop_float" + }, + "type": { + "primitiveType": "DT_FLOAT" + } + }, { + "propId": { + "name": "prop_double" + }, + "type": { + "primitiveType": "DT_DOUBLE" + } + }, { + "propId": { + "name": "prop_text" + }, + "type": { + "string": { + "longText": { + } + } + } + }, { + "propId": { + "name": "prop_char" + }, + "type": { + "string": { + "char": { + "fixedLength": 4 + } + } + } + }, { + "propId": { + "name": "prop_varchar" + }, + "type": { + "string": { + "varChar": { + "maxLength": 4 + } + } + } + }, { + "propId": { + "name": "prop_date" + }, + "type": { + "temporal": { + "date32": { + } + } + } + }, { + "propId": { + "name": "prop_ts" + }, + "type": { + "temporal": { + "timestamp": { + } + } + } + }] + }] + } + } + }] + }, { + "opr": { + "project": { + "mappings": [{ + "expr": { + "operators": [{ + "var": { + "tag": { + "id": 0 + }, + "property": { + "key": { + "name": "prop_double" + } + }, + "nodeType": { + "dataType": { + "primitiveType": "DT_DOUBLE" + } + } + }, + "nodeType": { + "dataType": { + "primitiveType": "DT_DOUBLE" + } + } + }] + }, + "alias": 1 + }] + } + }, + "metaData": [{ + "type": { + "dataType": { + "primitiveType": "DT_DOUBLE" + } + }, + "alias": 1 + }] + }, { + "opr": { + "sink": { + "tags": [{ + "tag": 1 + }], + "sinkTarget": { + "sinkDefault": { + } + } + } + } + }] +} diff --git a/interactive_engine/compiler/src/test/resources/proto/compare_uint64_uint64_test.json b/interactive_engine/compiler/src/test/resources/proto/compare_uint64_uint64_test.json new file mode 100644 index 000000000000..ac507ce23624 --- /dev/null +++ b/interactive_engine/compiler/src/test/resources/proto/compare_uint64_uint64_test.json @@ -0,0 +1,216 @@ +{ + "plan": [{ + "opr": { + "scan": { + "alias": 0, + "params": { + "tables": [{ + "id": 0 + }], + "predicate": { + "operators": [{ + "var": { + "property": { + "key": { + "name": "prop_uint64" + } + }, + "nodeType": { + "dataType": { + "primitiveType": "DT_UNSIGNED_INT64" + } + } + }, + "nodeType": { + "dataType": { + "primitiveType": "DT_UNSIGNED_INT64" + } + } + }, { + "logical": "EQ", + "nodeType": { + "dataType": { + "primitiveType": "DT_BOOL" + } + } + }, { + "const": { + "u64": "18446744073709551602" + }, + "nodeType": { + "dataType": { + "primitiveType": "DT_UNSIGNED_INT64" + } + } + }] + }, + "sampleRatio": 1.0 + } + } + }, + "metaData": [{ + "type": { + "graphType": { + "graphDataType": [{ + "label": { + }, + "props": [{ + "propId": { + "name": "prop_int32" + }, + "type": { + "primitiveType": "DT_SIGNED_INT32" + } + }, { + "propId": { + "name": "prop_uint32" + }, + "type": { + "primitiveType": "DT_UNSIGNED_INT32" + } + }, { + "propId": { + "name": "prop_int64" + }, + "type": { + "primitiveType": "DT_SIGNED_INT64" + } + }, { + "propId": { + "name": "prop_uint64" + }, + "type": { + "primitiveType": "DT_UNSIGNED_INT64" + } + }, { + "propId": { + "name": "prop_bool" + }, + "type": { + "primitiveType": "DT_BOOL" + } + }, { + "propId": { + "name": "prop_float" + }, + "type": { + "primitiveType": "DT_FLOAT" + } + }, { + "propId": { + "name": "prop_double" + }, + "type": { + "primitiveType": "DT_DOUBLE" + } + }, { + "propId": { + "name": "prop_text" + }, + "type": { + "string": { + "longText": { + } + } + } + }, { + "propId": { + "name": "prop_char" + }, + "type": { + "string": { + "char": { + "fixedLength": 4 + } + } + } + }, { + "propId": { + "name": "prop_varchar" + }, + "type": { + "string": { + "varChar": { + "maxLength": 4 + } + } + } + }, { + "propId": { + "name": "prop_date" + }, + "type": { + "temporal": { + "date32": { + } + } + } + }, { + "propId": { + "name": "prop_ts" + }, + "type": { + "temporal": { + "timestamp": { + } + } + } + }] + }] + } + } + }] + }, { + "opr": { + "project": { + "mappings": [{ + "expr": { + "operators": [{ + "var": { + "tag": { + "id": 0 + }, + "property": { + "key": { + "name": "prop_uint64" + } + }, + "nodeType": { + "dataType": { + "primitiveType": "DT_UNSIGNED_INT64" + } + } + }, + "nodeType": { + "dataType": { + "primitiveType": "DT_UNSIGNED_INT64" + } + } + }] + }, + "alias": 1 + }] + } + }, + "metaData": [{ + "type": { + "dataType": { + "primitiveType": "DT_UNSIGNED_INT64" + } + }, + "alias": 1 + }] + }, { + "opr": { + "sink": { + "tags": [{ + "tag": 1 + }], + "sinkTarget": { + "sinkDefault": { + } + } + } + } + }] +} diff --git a/interactive_engine/compiler/src/test/resources/proto/divide_int32_uint32_int32.json b/interactive_engine/compiler/src/test/resources/proto/divide_int32_uint32_int32.json new file mode 100644 index 000000000000..7d185c194268 --- /dev/null +++ b/interactive_engine/compiler/src/test/resources/proto/divide_int32_uint32_int32.json @@ -0,0 +1,183 @@ +{ + "plan": [{ + "opr": { + "scan": { + "alias": 0, + "params": { + "tables": [{ + "id": 0 + }], + "sampleRatio": 1.0 + } + } + }, + "metaData": [{ + "type": { + "graphType": { + "graphDataType": [{ + "label": { + }, + "props": [{ + "propId": { + "name": "prop_int32" + }, + "type": { + "primitiveType": "DT_SIGNED_INT32" + } + }, { + "propId": { + "name": "prop_uint32" + }, + "type": { + "primitiveType": "DT_UNSIGNED_INT32" + } + }, { + "propId": { + "name": "prop_int64" + }, + "type": { + "primitiveType": "DT_SIGNED_INT64" + } + }, { + "propId": { + "name": "prop_uint64" + }, + "type": { + "primitiveType": "DT_UNSIGNED_INT64" + } + }, { + "propId": { + "name": "prop_bool" + }, + "type": { + "primitiveType": "DT_BOOL" + } + }, { + "propId": { + "name": "prop_float" + }, + "type": { + "primitiveType": "DT_FLOAT" + } + }, { + "propId": { + "name": "prop_double" + }, + "type": { + "primitiveType": "DT_DOUBLE" + } + }, { + "propId": { + "name": "prop_text" + }, + "type": { + "string": { + "longText": { + } + } + } + }, { + "propId": { + "name": "prop_char" + }, + "type": { + "string": { + "char": { + "fixedLength": 4 + } + } + } + }, { + "propId": { + "name": "prop_varchar" + }, + "type": { + "string": { + "varChar": { + "maxLength": 4 + } + } + } + }, { + "propId": { + "name": "prop_date" + }, + "type": { + "temporal": { + "date32": { + } + } + } + }, { + "propId": { + "name": "prop_ts" + }, + "type": { + "temporal": { + "timestamp": { + } + } + } + }] + }] + } + } + }] + }, { + "opr": { + "project": { + "mappings": [{ + "expr": { + "operators": [{ + "const": { + "i32": 2 + }, + "nodeType": { + "dataType": { + "primitiveType": "DT_SIGNED_INT32" + } + } + }, { + "arith": "DIV", + "nodeType": { + "dataType": { + "primitiveType": "DT_UNSIGNED_INT64" + } + } + }, { + "const": { + "u64": "3" + }, + "nodeType": { + "dataType": { + "primitiveType": "DT_UNSIGNED_INT64" + } + } + }] + }, + "alias": 1 + }] + } + }, + "metaData": [{ + "type": { + "dataType": { + "primitiveType": "DT_UNSIGNED_INT64" + } + }, + "alias": 1 + }] + }, { + "opr": { + "sink": { + "tags": [{ + "tag": 1 + }], + "sinkTarget": { + "sinkDefault": { + } + } + } + } + }] +} diff --git a/interactive_engine/executor/ir/proto/common.proto b/interactive_engine/executor/ir/proto/common.proto index 14a07f03da4f..f3eb1f3d1d75 100644 --- a/interactive_engine/executor/ir/proto/common.proto +++ b/interactive_engine/executor/ir/proto/common.proto @@ -87,5 +87,8 @@ message Value { Date32 date = 14; Time32 time = 15; Timestamp timestamp = 16; + uint32 u32 = 17; + uint64 u64 = 18; + float f32 = 19; } } From 11eb9ab012e3aecb2841627f88271ecd5dbe9b42 Mon Sep 17 00:00:00 2001 From: shirly121 Date: Fri, 21 Feb 2025 11:46:11 +0800 Subject: [PATCH 09/17] minor fix minus tests --- .../flex/bench/FlexTypeQueries.java | 118 ++++++++---------- 1 file changed, 52 insertions(+), 66 deletions(-) diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeQueries.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeQueries.java index ff30db4898b6..36e438f50d09 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeQueries.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeQueries.java @@ -580,142 +580,128 @@ public QueryContext plus_float_double_test() { public class MinusTest { - // divide_int32_int32|2,1|2 + // minus_int32_int32|12,13|-1 /** - * Divide an int32 value by an int32 value, the result is within the range of int32. + * Minus an int32 value with an int32 value, the result is within the range of int32. * * Expected Results: - * The query should return an int32 type value, identical to the quotient of $1 and $2. + * The query should return an int32 type value, identical to the difference of $1 and $2. */ - public QueryContext divide_int32_int32_test() { - String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; - Parameter parameter = queryParameters.get("divide_int32_int32"); + public QueryContext minus_int32_int32_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 - $2"; + Parameter parameter = queryParameters.get("minus_int32_int32"); query = parameter.render(query); return new QueryContext(query, parameter.results); } - // divide_int32_int32_overflow|-2147483648,-1|overflow + // minus_int32_int32_overflow|2147483647,-1|overflow /** - * Divide an int32 value by an int32 value, the result exceeds the range of int32. + * Minus an int32 value with an int32 value, the result exceeds the range of int32. * * Expected Results: * The query should throw an overflow exception due to int32 overflow. */ - public QueryContext divide_int32_int32_overflow_test() { - String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; - Parameter parameter = queryParameters.get("divide_int32_int32_overflow"); + public QueryContext minus_int32_int32_overflow_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 - $2"; + Parameter parameter = queryParameters.get("minus_int32_int32_overflow"); query = parameter.render(query); return new QueryContext(query, parameter.results); } - // divide_int32_uint32_int32|2,+1|2 + // minus_int32_uint32_int32|12,+13|-1 /** - * Divide an int32 value by an uint32 value, the result is within the range of int32. + * Minus an int32 value with an uint32 value, the result is within the range of int32. * * Expected Results: - * The query should return an int32 type value, identical to the quotient of $1 and $2. + * The query should return an int32 type value, identical to the difference of $1 and $2. */ - public QueryContext divide_int32_uint32_int32_test() { - String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; - Parameter parameter = queryParameters.get("divide_int32_uint32_int32"); + public QueryContext minus_int32_uint32_int32_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 - $2"; + Parameter parameter = queryParameters.get("minus_int32_uint32_int32"); query = parameter.render(query); return new QueryContext(query, parameter.results); } - // divide_uint32_int32_uint32|+4294967295,1|+4294967295 + // minus_uint32_int32_uint32|+2147483647,-10|+2147483657 /** - * Divide an uint32 value by an int32 value, the result is out of the range of int32 but within the range of uint32. + * Minus an uint32 value with an int32 value, the result is within the range of uint32. * * Expected Results: - * The query should return a uint32 type value, identical to the quotient of $1 and $2. + * The query should return an uint32 type value, identical to the difference of $1 and $2. */ - public QueryContext divide_uint32_int32_uint32_test() { - String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; - Parameter parameter = queryParameters.get("divide_uint32_int32_uint32"); + public QueryContext minus_uint32_int32_uint32_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 - $2"; + Parameter parameter = queryParameters.get("minus_uint32_int32_uint32"); query = parameter.render(query); return new QueryContext(query, parameter.results); } - // divide_uint32_int32_overflow|+4294967295,-1|overflow + // minus_uint32_int32_overflow|+4294967295,-1|overflow /** - * Divide an uint32 value by a negative int32 value, the result exceeds the range of int32 (SIGNED_INT32_MIN). + * Minus an uint32 value with an int32 value, the result exceeds the range of uint32. * * Expected Results: - * The query should throw an overflow exception due to int32 overflow. + * The query should throw an overflow exception due to uint32 overflow. */ - public QueryContext divide_uint32_int32_overflow_test() { - String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; - Parameter parameter = queryParameters.get("divide_uint32_int32_overflow"); + public QueryContext minus_uint32_int32_overflow_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 - $2"; + Parameter parameter = queryParameters.get("minus_uint32_int32_overflow"); query = parameter.render(query); return new QueryContext(query, parameter.results); } - // divide_int32_int64|2,1L|2L + // minus_int32_int64|12,13L|-1L /** - * Divide an int32 value by an int64 value, the result is within the range of int64. + * Minus an int32 value with an int64 value, the result is within the range of int64. * * Expected Results: - * The query should return an int64 type value, identical to the quotient of $1 and $2. + * The query should return an int64 type value, identical to the difference of $1 and $2. */ - public QueryContext divide_int32_int64_test() { - String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; - Parameter parameter = queryParameters.get("divide_int32_int64"); + public QueryContext minus_int32_int64_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 - $2"; + Parameter parameter = queryParameters.get("minus_int32_int64"); query = parameter.render(query); return new QueryContext(query, parameter.results); } - // divide_int64_int32_overflow|-9223372036854775808L,-1|overflow + // minus_int64_int32_overflow|9223372036854775807L,-10|overflow /** - * Divide an int64 value by an int32 value, the result exceeds the range of int64. + * Minus an int64 value with an int32 value, the result exceeds the range of int64. * * Expected Results: * The query should throw an overflow exception due to int64 overflow. */ - public QueryContext divide_int64_int32_overflow_test() { - String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; - Parameter parameter = queryParameters.get("divide_int64_int32_overflow"); + public QueryContext minus_int64_int32_overflow_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 - $2"; + Parameter parameter = queryParameters.get("minus_int64_int32_overflow"); query = parameter.render(query); return new QueryContext(query, parameter.results); } - // divide_int32_double|2,1.12d|1.77d + // minus_int32_double|12,13.12d|-1.12d /** - * Divide an int32 value by a double value, the result is within the range of double. + * Minus an int32 value with a double value, the result is within the range of double. * * Expected Results: - * The query should return a double type value, identical to the quotient of $1 and $2. + * The query should return a double type value, identical to the difference of $1 and $2. */ - public QueryContext divide_int32_double_test() { - String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; - Parameter parameter = queryParameters.get("divide_int32_double"); + public QueryContext minus_int32_double_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 - $2"; + Parameter parameter = queryParameters.get("minus_int32_double"); query = parameter.render(query); return new QueryContext(query, parameter.results); } - // divide_float_double|2.0f,1.12d|1.78d + // minus_float_double|12.0f,13.12d|-1.12d /** - * Divide a float value by a double value, the result is within the range of double. + * Minus a float value with a double value, the result is within the range of double. * * Expected Results: - * The query should return a double type value, identical to the quotient of $1 and $2. + * The query should return a double type value, identical to the difference of $1 and $2. */ - public QueryContext divide_float_double_test() { - String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; - Parameter parameter = queryParameters.get("divide_float_double"); - query = parameter.render(query); - return new QueryContext(query, parameter.results); - } - - // divide_float_double_NaN|2.0f,0.0d|NaN - /** - * Divide a float value by a double value, where the divisor is zero, resulting in NaN. - * - * Expected Results: - * The query should return NaN as the result of division by zero. - */ - public QueryContext divide_float_double_NaN_test() { - String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 / $2"; - Parameter parameter = queryParameters.get("divide_float_double_NaN"); + public QueryContext minus_float_double_test() { + String query = "MATCH (p:person {prop_int32: 933})\n" + " RETURN $1 - $2"; + Parameter parameter = queryParameters.get("minus_float_double"); query = parameter.render(query); return new QueryContext(query, parameter.results); } From 504bfc4df4965d65b973b9627a74071654633c83 Mon Sep 17 00:00:00 2001 From: shirly121 Date: Fri, 21 Feb 2025 13:23:09 +0800 Subject: [PATCH 10/17] fix uint32 value checking in flex bench --- .../cypher/result/CypherRecordParser.java | 7 ++++--- .../graphscope/cypher/antlr4/Utils.java | 7 +++++++ .../integration/flex/bench/FlexTypeTest.java | 19 ++++++++++++++----- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/result/CypherRecordParser.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/result/CypherRecordParser.java index d5752d2a652a..d26074ed9baf 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/result/CypherRecordParser.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/result/CypherRecordParser.java @@ -304,9 +304,10 @@ protected AnyValue parseValue(Common.Value value, @Nullable RelDataType dataType case I64: return Values.longValue(value.getI64()); case U32: - // cypher does not support u32 directly, represent u32 as long, which is enough to - // hold u32 value. - return Values.longValue(value.getU32()); + // cypher does not support u32 directly, represent u32 as int, + // user need to convert int to u32 and handle the overflow cases at the + // client-side. + return Values.intValue(value.getU32()); case U64: // cypher does not support u64 directly, represent u64 as long, // user need to convert long to u64 and handle the overflow cases at the diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/Utils.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/Utils.java index 36bd72b25e4b..3ad777055b45 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/Utils.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/Utils.java @@ -58,4 +58,11 @@ public static byte[] longToBytes(long value) { buffer.putLong(value); return buffer.array(); } + + public static byte[] intToBytes(int value) { + ByteBuffer buffer = ByteBuffer.allocate(4); + buffer.order(ByteOrder.BIG_ENDIAN); + buffer.putInt(value); + return buffer.array(); + } } diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java index 2e5b642aa63b..514a38e42308 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java @@ -141,7 +141,7 @@ private void checkResult(Supplier resultSupplier, QueryContext ctx) { } } else { List records = resultSupplier.get().list(); - Assert.assertEquals(1, records.size()); + Assert.assertTrue("records should not be empty", !records.isEmpty()); Record single = records.get(0); Assert.assertEquals(expected.size(), single.size()); for (int i = 0; i < expected.size(); i++) { @@ -152,11 +152,15 @@ private void checkResult(Supplier resultSupplier, QueryContext ctx) { expectedValue = expectedValue.substring(1); unsigned = true; } + boolean int32 = true; + if (expectedValue.toLowerCase().endsWith("l")) { + int32 = false; + } String upperCase = expectedValue.toUpperCase(); if (upperCase.endsWith("L") || upperCase.endsWith("D") || upperCase.endsWith("F")) { expectedValue = expectedValue.substring(0, expectedValue.length() - 1); } - String actualValue = getActualValue(actual, unsigned); + String actualValue = getActualValue(actual, unsigned, int32); Assert.assertEquals(expectedValue, actualValue); } } @@ -167,10 +171,15 @@ public static void tearDown() { session.close(); } - public String getActualValue(Value actual, boolean unsigned) { + public String getActualValue(Value actual, boolean unsigned, boolean int32) { if (unsigned) { - long value = actual.asLong(); - return new BigDecimal(new BigInteger(1, Utils.longToBytes(value))).toString(); + if (int32) { + int value = actual.asInt(); + return new BigDecimal(new BigInteger(1, Utils.intToBytes(value))).toString(); + } else { + long value = actual.asLong(); + return new BigDecimal(new BigInteger(1, Utils.longToBytes(value))).toString(); + } } return actual.toString(); } From 988367a39f32bd2bfbb87dbc836dc75f192d4a3d Mon Sep 17 00:00:00 2001 From: "bingqing.lbq" Date: Fri, 21 Feb 2025 15:46:59 +0800 Subject: [PATCH 11/17] minor fix wrong expected results Committed-by: bingqing.lbq from Dev container --- .../compiler/src/test/resources/flex_bench/parameters | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interactive_engine/compiler/src/test/resources/flex_bench/parameters b/interactive_engine/compiler/src/test/resources/flex_bench/parameters index 0caa4c50f4ce..2e8e6fca5f90 100644 --- a/interactive_engine/compiler/src/test/resources/flex_bench/parameters +++ b/interactive_engine/compiler/src/test/resources/flex_bench/parameters @@ -38,7 +38,7 @@ plus_float_double|12.0f,16.23d|28.23d minus_int32_int32|12,13|-1 minus_int32_int32_overflow|2147483647,-1|overflow -minus_int32_uint32_int32|12,+13|-1 +minus_int32_uint32_int32|13,+12|+1 minus_uint32_int32_uint32|+2147483647,-10|+2147483657 minus_uint32_int32_overflow|+4294967295,-1|overflow minus_int32_int64|12,13L|-1L @@ -63,8 +63,8 @@ divide_uint32_int32_uint32|+4294967295,1|+4294967295 divide_uint32_int32_overflow|+4294967295,-1|overflow divide_int32_int64|2,1L|2L divide_int64_int32_overflow|-9223372036854775808L,-1|overflow -divide_int32_double|2,1.12d|1.77d -divide_float_double|2.0f,1.12d|1.78d +divide_int32_double|2,1.12d|1.79d +divide_float_double|2.0f,1.12d|1.79d divide_float_double_NaN|2.0f,0.0d|NaN get_knows_between_two_persons|32,33|32,33 From 81c49284016942a146ba4c9698ec12d71fa0b3b0 Mon Sep 17 00:00:00 2001 From: shirly121 Date: Fri, 21 Feb 2025 15:53:30 +0800 Subject: [PATCH 12/17] fix incorrect type of integer -2147483648 --- .../antlr4/visitor/ExpressionVisitor.java | 28 +++++++++------ .../cypher/antlr4/visitor/LiteralVisitor.java | 9 ++++- .../graphscope/cypher/antlr4/MatchTest.java | 2 +- .../graphscope/cypher/antlr4/TypeTest.java | 35 +++++++++++++++++++ 4 files changed, 62 insertions(+), 12 deletions(-) diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/ExpressionVisitor.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/ExpressionVisitor.java index 72518e44a860..a0b7cdae81d9 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/ExpressionVisitor.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/ExpressionVisitor.java @@ -225,13 +225,24 @@ public ExprVisitorResult visitOC_MultiplyDivideModuloExpression( public ExprVisitorResult visitOC_UnaryAddOrSubtractExpression( CypherGSParser.OC_UnaryAddOrSubtractExpressionContext ctx) { String text = ctx.getText().toLowerCase(); - // convert unary add to unsigned integer if (text.startsWith("+")) { - String value = text.substring(1); - if (text.endsWith("l")) { - value = value.substring(0, value.length() - 1); - } - BigDecimal decimal = new BigDecimal(value); + text = text.substring(1); + } + Object integerValue; + try { + // check the expr is actual an integer value. + integerValue = LiteralVisitor.INSTANCE.parseInteger(text); + } catch (Exception e) { + // if not an integer, i.e. -a.age, then convert to the normal expression + ExprVisitorResult operand = + visitOC_ListOperatorExpression(ctx.oC_ListOperatorExpression()); + List operators = + Utils.getOperators(ctx.children, ImmutableList.of("-", "+"), true); + return Utils.unaryCall(operators, operand, builder); + } + // parse to unsigned types + if (ctx.getText().startsWith("+")) { + BigDecimal decimal = new BigDecimal(integerValue.toString()); RelDataType type; if (decimal.compareTo(IrDataTypeConvertor.UINT32_MAX) <= 0 && !text.endsWith("l")) { type = @@ -253,10 +264,7 @@ public ExprVisitorResult visitOC_UnaryAddOrSubtractExpression( } return new ExprVisitorResult(builder.getRexBuilder().makeLiteral(decimal, type)); } - ExprVisitorResult operand = visitOC_ListOperatorExpression(ctx.oC_ListOperatorExpression()); - List operators = - Utils.getOperators(ctx.children, ImmutableList.of("-", "+"), true); - return Utils.unaryCall(operators, operand, builder); + return new ExprVisitorResult(builder.literal(integerValue)); } @Override diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/LiteralVisitor.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/LiteralVisitor.java index c131af45f7c7..3d2d7889b55b 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/LiteralVisitor.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/antlr4/visitor/LiteralVisitor.java @@ -36,7 +36,11 @@ public Object visitOC_BooleanLiteral(CypherGSParser.OC_BooleanLiteralContext ctx @Override public Object visitOC_IntegerLiteral(CypherGSParser.OC_IntegerLiteralContext ctx) { - String integerLiteral = ctx.getText().toLowerCase(); + return parseInteger(ctx.getText()); + } + + public Object parseInteger(String text) { + String integerLiteral = text.toLowerCase(); try { if (integerLiteral.length() > 1) { char lastChar = integerLiteral.charAt(integerLiteral.length() - 1); @@ -75,6 +79,9 @@ public Object visitOC_IntegerLiteral(CypherGSParser.OC_IntegerLiteralContext ctx } else if (integerLiteral.charAt(startIndex) == '0') { radix = 8; } + if (integerLiteral.endsWith("l")) { + integerLiteral = integerLiteral.substring(0, integerLiteral.length() - 1); + } // create big integer return new BigInteger(integerLiteral, radix); } diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/MatchTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/MatchTest.java index 7c4189d46e88..3e0ff757a6fb 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/MatchTest.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/MatchTest.java @@ -696,7 +696,7 @@ public void optional_shortest_path_test() { RelNode after = optimizer.optimize(node, new GraphIOProcessor(builder, irMeta)); Assert.assertEquals( "GraphLogicalProject(len=[len], isAppend=[false])\n" - + " GraphLogicalProject(len=[CASE(IS NULL(k), -(1), k.~len)]," + + " GraphLogicalProject(len=[CASE(IS NULL(k), -1, k.~len)]," + " isAppend=[false])\n" + " GraphLogicalGetV(tableConfig=[{isAll=false, tables=[person]}]," + " alias=[p2], fusedFilter=[[=(_.id, ?1)]], opt=[END])\n" diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/TypeTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/TypeTest.java index 73e2ba1dbc95..c844e44643c3 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/TypeTest.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/TypeTest.java @@ -95,6 +95,41 @@ public void compare_double_float_test() { builder1.build().explain().trim()); } + @Test + public void divide_int32_int32_overflow_test() { + GraphBuilder builder = + com.alibaba.graphscope.common.ir.Utils.mockGraphBuilder(optimizer, irMeta); + builder.disableSimplify(); + RelNode before = + com.alibaba.graphscope.cypher.antlr4.Utils.eval( + "MATCH (p:person)\n" + " RETURN -2147483648 / -1", builder) + .build(); + RelNode after = optimizer.optimize(before, new GraphIOProcessor(builder, irMeta)); + Assert.assertEquals( + "GraphLogicalProject($f0=[/(-2147483648, -1)], isAppend=[false])\n" + + " GraphLogicalSource(tableConfig=[{isAll=false, tables=[person]}]," + + " alias=[p], opt=[VERTEX])", + after.explain().trim()); + } + + @Test + public void divide_int64_int32_overflow_test() { + GraphBuilder builder = + com.alibaba.graphscope.common.ir.Utils.mockGraphBuilder(optimizer, irMeta); + builder.disableSimplify(); + RelNode before = + com.alibaba.graphscope.cypher.antlr4.Utils.eval( + "MATCH (p:person)\n" + " RETURN -9223372036854775808L / -1", + builder) + .build(); + RelNode after = optimizer.optimize(before, new GraphIOProcessor(builder, irMeta)); + Assert.assertEquals( + "GraphLogicalProject($f0=[/(-9223372036854775808:BIGINT, -1)], isAppend=[false])\n" + + " GraphLogicalSource(tableConfig=[{isAll=false, tables=[person]}]," + + " alias=[p], opt=[VERTEX])", + after.explain().trim()); + } + @Test public void convert_int32_to_uint32_test() { BigDecimal expected = new BigDecimal("4294967284"); From 1650049d398d41cbf3d59b942a43be28bac53cf1 Mon Sep 17 00:00:00 2001 From: shirly121 Date: Tue, 25 Feb 2025 16:02:17 +0800 Subject: [PATCH 13/17] allow type comparsion between date32 and int32 --- .../ir/tools/GraphStdOperatorTable.java | 2 +- .../graphscope/common/ir/QueryCacheTest.java | 8 +- .../graphscope/cypher/antlr4/TypeTest.java | 53 +++++++- .../flex/bench/FlexTypeQueries.java | 122 ++++++++++++++++-- .../src/test/resources/flex_bench/parameters | 6 + 5 files changed, 170 insertions(+), 21 deletions(-) diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/GraphStdOperatorTable.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/GraphStdOperatorTable.java index 307ccf1dbd2e..6337c295bfc2 100644 --- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/GraphStdOperatorTable.java +++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/tools/GraphStdOperatorTable.java @@ -191,7 +191,7 @@ public class GraphStdOperatorTable extends SqlStdOperatorTable { true, ReturnTypes.BOOLEAN_NULLABLE, GraphInferTypes.FIRST_KNOWN, - OperandTypes.COMPARABLE_UNORDERED_COMPARABLE_UNORDERED); + OperandTypes.or(OperandTypes.DATETIME_INTERVAL, OperandTypes.COMPARABLE_UNORDERED_COMPARABLE_UNORDERED)); public static final SqlBinaryOperator NOT_EQUALS = new SqlBinaryOperator( diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/QueryCacheTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/QueryCacheTest.java index 16540c2ab9e7..c6f36e83c2a2 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/QueryCacheTest.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/common/ir/QueryCacheTest.java @@ -37,7 +37,7 @@ public class QueryCacheTest { // test hash code of query cache key @Test public void query_cache_1_test() { - Configs configs = new Configs(ImmutableMap.of("query.cache.size", "1")); + Configs configs = new Configs(ImmutableMap.of("query.cache.size", "1", "graph.physical.opt", "proto")); GraphPlanner graphPlanner = new GraphPlanner( configs, new LogicalPlanFactory.Cypher(), new GraphRelOptimizer(configs)); @@ -63,7 +63,7 @@ public void query_cache_1_test() { // test evict strategy of query cache @Test public void query_cache_2_test() throws Exception { - Configs configs = new Configs(ImmutableMap.of("query.cache.size", "1")); + Configs configs = new Configs(ImmutableMap.of("query.cache.size", "1", "graph.physical.opt", "proto")); GraphPlanner graphPlanner = new GraphPlanner( configs, new LogicalPlanFactory.Cypher(), new GraphRelOptimizer(configs)); @@ -86,7 +86,7 @@ public void query_cache_2_test() throws Exception { @Test public void query_cache_3_test() { - Configs configs = new Configs(ImmutableMap.of("query.cache.size", "10")); + Configs configs = new Configs(ImmutableMap.of("query.cache.size", "10", "graph.physical.opt", "proto")); GraphPlanner graphPlanner = new GraphPlanner( configs, new LogicalPlanFactory.Gremlin(), new GraphRelOptimizer(configs)); @@ -105,7 +105,7 @@ public void query_cache_3_test() { // test cache invalidation after schema update @Test public void query_cache_schema_update_test() throws Exception { - Configs configs = new Configs(ImmutableMap.of()); + Configs configs = new Configs(ImmutableMap.of("graph.physical.opt", "proto")); GraphPlanner graphPlanner = new GraphPlanner( configs, new LogicalPlanFactory.Cypher(), new GraphRelOptimizer(configs)); diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/TypeTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/TypeTest.java index c844e44643c3..93ab7cf1a7fc 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/TypeTest.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/antlr4/TypeTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.alibaba.graphscope.cypher.antlr4; +package com.alibaba.graphscope.cypher.integration.flex.bench; import com.alibaba.graphscope.common.config.Configs; import com.alibaba.graphscope.common.ir.meta.IrMeta; @@ -24,6 +24,7 @@ import com.alibaba.graphscope.common.ir.tools.GraphBuilder; import com.alibaba.graphscope.common.ir.tools.LogicalPlan; import com.alibaba.graphscope.common.utils.FileUtils; +import com.alibaba.graphscope.cypher.antlr4.Utils; import com.google.common.collect.ImmutableMap; import org.apache.calcite.rel.RelNode; @@ -34,7 +35,7 @@ import java.math.BigDecimal; import java.math.BigInteger; -public class TypeTest { +public class UnitTypeTest { private static Configs configs; private static IrMeta irMeta; private static GraphRelOptimizer optimizer; @@ -175,4 +176,52 @@ public void divide_int32_uint64_test() { FileUtils.readJsonFromResource("proto/divide_int32_uint32_int32.json"), builder1.build().explain().trim()); } + + @Test + public void compare_date32_i32_test() { + GraphBuilder builder = + com.alibaba.graphscope.common.ir.Utils.mockGraphBuilder(optimizer, irMeta); + RelNode before = + com.alibaba.graphscope.cypher.antlr4.Utils.eval( + "MATCH (p:person)\n" + + " WHERE p.prop_date = 20132\n" + + " RETURN p.prop_date", + builder) + .build(); + RelNode after = optimizer.optimize(before, new GraphIOProcessor(builder, irMeta)); + Assert.assertEquals("GraphLogicalProject(prop_date=[p.prop_date], isAppend=[false])\n" + + " GraphLogicalSource(tableConfig=[{isAll=false, tables=[person]}], alias=[p], fusedFilter=[[=(_.prop_date, 20132)]], opt=[VERTEX])", after.explain().trim()); + } + + @Test + public void compare_timestamp_i64_test() { + GraphBuilder builder = + com.alibaba.graphscope.common.ir.Utils.mockGraphBuilder(optimizer, irMeta); + RelNode before = + com.alibaba.graphscope.cypher.antlr4.Utils.eval( + "MATCH (p:person)\n" + + " WHERE p.prop_ts = 1739454301000L\n" + + " RETURN p.prop_ts", + builder) + .build(); + RelNode after = optimizer.optimize(before, new GraphIOProcessor(builder, irMeta)); + Assert.assertEquals("GraphLogicalProject(prop_ts=[p.prop_ts], isAppend=[false])\n" + + " GraphLogicalSource(tableConfig=[{isAll=false, tables=[person]}], alias=[p], fusedFilter=[[=(_.prop_ts, 1739454301000:BIGINT)]], opt=[VERTEX])", after.explain().trim()); + } + + @Test + public void compare_int32_int64_array_test() { + String query = + "MATCH (p:person) Where p.prop_int32 in [123L, 456] RETURN p.prop_int32"; + GraphBuilder builder = + com.alibaba.graphscope.common.ir.Utils.mockGraphBuilder(optimizer, irMeta); + RelNode before = + com.alibaba.graphscope.cypher.antlr4.Utils.eval( + query, + builder) + .build(); + RelNode after = optimizer.optimize(before, new GraphIOProcessor(builder, irMeta)); + Assert.assertEquals("GraphLogicalProject(prop_int32=[p.prop_int32], isAppend=[false])\n" + + " GraphLogicalSource(tableConfig=[{isAll=false, tables=[person]}], alias=[p], opt=[VERTEX], uniqueKeyFilters=[SEARCH(_.prop_int32, Sarg[123L:BIGINT, 456L:BIGINT]:BIGINT)])", after.explain().trim()); + } } diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeQueries.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeQueries.java index 36e438f50d09..a47187488329 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeQueries.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeQueries.java @@ -18,6 +18,7 @@ import com.alibaba.graphscope.cypher.integration.suite.QueryContext; import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.apache.commons.io.FileUtils; @@ -26,28 +27,21 @@ import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; public class FlexTypeQueries { private final Map queryParameters; - private static class Parameter { - private final String name; - private final List parameters; - private final List results; + public static class Parameter { + public final String name; + public final List parameters; + public final List results; public Parameter(String line) { String[] parts = line.split("\\|"); Preconditions.checkArgument(parts.length >= 3, "invalid parameter line: " + line); this.name = parts[0].trim(); - this.parameters = - List.of(parts[1].trim().split(",")).stream() - .map(k -> k.trim()) - .collect(Collectors.toList()); - this.results = - List.of(parts[2].trim().split(",")).stream() - .map(k -> k.trim()) - .collect(Collectors.toList()); + this.parameters = parseParameters(parts[1].trim()); + this.results = parseParameters(parts[2].trim()); } public String render(String template) { @@ -56,6 +50,42 @@ public String render(String template) { } return template; } + + private List parseParameters(String input) { + List result = Lists.newArrayList(); + StringBuilder token = new StringBuilder(); + int bracketLevel = 0; + + for (int i = 0; i < input.length(); i++) { + char ch = input.charAt(i); + if (ch == '[') { + if (bracketLevel == 0 && token.length() > 0) { + result.add(token.toString().trim()); + token.setLength(0); + } + bracketLevel++; + } else if (ch == ']') { + bracketLevel--; + } + + if (bracketLevel > 0 || ch != ',') { + token.append(ch); + } + + if (ch == ',' && bracketLevel == 0) { + if (token.length() > 0) { + result.add(token.toString().trim()); + token.setLength(0); + } + } + } + + if (token.length() > 0) { + result.add(token.toString()); + } + + return result; + } } public FlexTypeQueries(String inputPath) throws Exception { @@ -444,11 +474,75 @@ public QueryContext compare_date32_i32_test() { */ public QueryContext compare_timestamp_i64_test() { String query = - "MATCH (p:person)\n" + " WHERE p.prop_ts = $1\n" + " RETURN p.prop_ts"; + "MATCH (p:person)\n" + + " WHERE p.prop_ts = $1\n" + + " RETURN p.prop_ts"; Parameter parameter = queryParameters.get("compare_timestamp_i64"); query = parameter.render(query); return new QueryContext(query, parameter.results); } + + /** + * Check the property value is one of the element in the given i32 array. + * The prop_int32 is the primary key, which will be converted to index predicate in physical proto. + * The execution layer should handle the primary key of within in the index predicate correctly. + * @return + */ + public QueryContext compare_i32_within_i32_array_test() { + String query = + "MATCH (p:person) Where p.prop_int32 in $1 RETURN p.prop_int32"; + Parameter parameter = queryParameters.get("compare_i32_within_i32_array"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Check the property value is one of the element in the given i64 array. + * @return + */ + public QueryContext compare_i32_within_i64_array_test() { + String query = + "MATCH (p:person) Where p.prop_int32 in $1 RETURN p.prop_int32"; + Parameter parameter = queryParameters.get("compare_i32_within_i64_array"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Check the property value is one of the element in the given i32 array. + * @return + */ + public QueryContext compare_i64_within_i32_array_test() { + String query = + "MATCH (p:person) Where p.prop_int64 in $1 RETURN p.prop_int64"; + Parameter parameter = queryParameters.get("compare_i64_within_i32_array"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Check the property value is one of the element in the given double array. + * @return + */ + public QueryContext compare_float_within_double_array_test() { + String query = + "MATCH (p:person) Where p.prop_float in $1 RETURN p.prop_float"; + Parameter parameter = queryParameters.get("compare_float_within_double_array"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } + + /** + * Check the property value is one of the element in the given string array. + * @return + */ + public QueryContext compare_char_within_string_array_test() { + String query = + "MATCH (p:person) Where p.prop_char in $1 RETURN p.prop_char"; + Parameter parameter = queryParameters.get("compare_char_within_string_array"); + query = parameter.render(query); + return new QueryContext(query, parameter.results); + } } public class PlusTest { diff --git a/interactive_engine/compiler/src/test/resources/flex_bench/parameters b/interactive_engine/compiler/src/test/resources/flex_bench/parameters index 2e8e6fca5f90..ebe02ea722ca 100644 --- a/interactive_engine/compiler/src/test/resources/flex_bench/parameters +++ b/interactive_engine/compiler/src/test/resources/flex_bench/parameters @@ -69,4 +69,10 @@ divide_float_double_NaN|2.0f,0.0d|NaN get_knows_between_two_persons|32,33|32,33 +compare_i32_within_i32_array|[32,123]|32 +compare_i32_within_i64_array|[32L,123L]|32 +compare_i64_within_i32_array|[1234567890,12]|1234567890L +compare_float_within_double_array|[3.14d,6.71d,8.90d]|3.14f +compare_char_within_string_array|["abcde","cdefg"]|"abcd" + From b7938aba730f4aa56a902f6fff53eeefea4368c9 Mon Sep 17 00:00:00 2001 From: "xiaolei.zl" Date: Wed, 5 Mar 2025 11:54:18 +0800 Subject: [PATCH 14/17] add type_test suite for interactive Committed-by: xiaolei.zl from Dev container --- .github/workflows/interactive.yml | 12 +++ flex/tests/hqps/hqps_type_test.sh | 94 +++++++++++++++++++ .../src/test/resources/flex_bench/import.yaml | 40 ++++++++ 3 files changed, 146 insertions(+) create mode 100644 flex/tests/hqps/hqps_type_test.sh create mode 100644 interactive_engine/compiler/src/test/resources/flex_bench/import.yaml diff --git a/.github/workflows/interactive.yml b/.github/workflows/interactive.yml index 35268f669bb3..b95d9c44955d 100644 --- a/.github/workflows/interactive.yml +++ b/.github/workflows/interactive.yml @@ -156,6 +156,9 @@ jobs: cp ${GITHUB_WORKSPACE}/flex/interactive/examples/new_graph_algo/import.yaml ${INTERACTIVE_WORKSPACE}/data/new_graph_algo/import.yaml mkdir -p ${INTERACTIVE_WORKSPACE}/data/modern_graph cp ${GITHUB_WORKSPACE}/flex/interactive/examples/modern_graph/graph.yaml ${INTERACTIVE_WORKSPACE}/data/modern_graph/graph.yaml + mkdir -p ${INTERACTIVE_WORKSPACE}/data/type_test + cp ${GITHUB_WORKSPACE}/interactive_engine/compiler/src/test/resources/flex_bench/modern.yaml ${INTERACTIVE_WORKSPACE}/data/type_test/graph.yaml + cp ${GITHUB_WORKSPACE}/interactive_engine/compiler/src/test/resources/flex_bench/import.yaml ${INTERACTIVE_WORKSPACE}/data/type_test/import.yaml # load graph cd ${GITHUB_WORKSPACE}/flex/build @@ -169,6 +172,15 @@ jobs: GLOG_v=10 ./bin/bulk_loader -g ${INTERACTIVE_WORKSPACE}/data/new_graph_algo/graph.yaml -l ${INTERACTIVE_WORKSPACE}/data/new_graph_algo/import.yaml -d ${INTERACTIVE_WORKSPACE}/data/new_graph_algo/indices/ export FLEX_DATA_DIR=../interactive/examples/modern_graph GLOG_v=10 ./bin/bulk_loader -g ${INTERACTIVE_WORKSPACE}/data/modern_graph/graph.yaml -l ../interactive/examples/modern_graph/bulk_load.yaml -d ${INTERACTIVE_WORKSPACE}/data/modern_graph/indices/ + export FLEX_DATA_DIR=${GITHUB_WORKSPACE}/interactive_engine/compiler/src/test/resources/flex_bench/data + GLOG_v=10 ./bin/bulk_loader -g ${INTERACTIVE_WORKSPACE}/data/type_test/graph.yaml -l ${INTERACTIVE_WORKSPACE}/data/type_test/import.yaml -d ${INTERACTIVE_WORKSPACE}/data/type_test/indices/ + + - name: Interactive Type Test + env: + INTERACTIVE_WORKSPACE: /tmp/interactive_workspace + run: | + cd ${GITHUB_WORKSPACE}/flex/tests/hqps + bash hqps_type_test.sh ${INTERACTIVE_WORKSPACE} ./interactive_config_test.yaml - name: Test HQPS admin http service env: diff --git a/flex/tests/hqps/hqps_type_test.sh b/flex/tests/hqps/hqps_type_test.sh new file mode 100644 index 000000000000..13a322f72c84 --- /dev/null +++ b/flex/tests/hqps/hqps_type_test.sh @@ -0,0 +1,94 @@ +#!/bin/bash +# Copyright 2020 Alibaba Group Holding Limited. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +set -e +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) +FLEX_HOME=${SCRIPT_DIR}/../../ +BULK_LOADER=${FLEX_HOME}/build/bin/bulk_loader +SERVER_BIN=${FLEX_HOME}/build/bin/interactive_server +GIE_HOME=${FLEX_HOME}/../interactive_engine/ + +# +if [ $# -ne 2 ]; then + echo "Receives: $# args, need 2 args" + echo "Usage: $0 " + exit 1 +fi + +INTERACTIVE_WORKSPACE=$1 +ENGINE_CONFIG_PATH=$2 + + +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' # No Color +err() { + echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] -ERROR- $* ${NC}" >&2 +} + +info() { + echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] -INFO- $* ${NC}" +} + + +kill_service(){ + info "Kill Service first" + ps -ef | grep "com.alibaba.graphscope.GraphServer" | awk '{print $2}' | xargs kill -9 || true + ps -ef | grep "interactive_server" | awk '{print $2}' | xargs kill -9 || true + sleep 3 + # check if service is killed + info "Kill Service success" +} + +# kill service when exit +trap kill_service EXIT + + +# start engine service and load ldbc graph +start_engine_service(){ + # suppose graph has been loaded, check ${GRAPH_CSR_DATA_DIR} exists + + #check SERVER_BIN exists + if [ ! -f ${SERVER_BIN} ]; then + err "SERVER_BIN not found" + exit 1 + fi + cmd="${SERVER_BIN} -c ${ENGINE_CONFIG_PATH} --start-compiler true " + cmd="${cmd} -w ${INTERACTIVE_WORKSPACE} --enable-admin-service true > /tmp/engine.log 2>&1 &" + + info "Start engine service with command: ${cmd}" + ${cmd} & + sleep 5 + #check interactive_server is running, if not, exit + ps -ef | grep "interactive_server" | grep -v grep + + info "Start engine service success" +} + + + +run_type_test() { + echo "run type test" + pushd ${GIE_HOME}/compiler + cmd="mvn test -Dtest=com.alibaba.graphscope.cypher.integration.flex.bench.FlexTypeTest" + info "Run type test with command: ${cmd}" + ${cmd} + info "Run type test success" + popd +} + +kill_service +start_engine_service +run_type_test +kill_service diff --git a/interactive_engine/compiler/src/test/resources/flex_bench/import.yaml b/interactive_engine/compiler/src/test/resources/flex_bench/import.yaml new file mode 100644 index 000000000000..08768cf7e8ad --- /dev/null +++ b/interactive_engine/compiler/src/test/resources/flex_bench/import.yaml @@ -0,0 +1,40 @@ +graph: modern_graph +loading_config: + data_source: + scheme: file # file, oss, s3, hdfs; only file is supported now + #location: /home/graphscope/gs_interactive_default_graph/ + import_option: init # append, overwrite, only init is supported now + format: + type: csv + metadata: + delimiter: "," # other loading configuration places here + header_row: true # whether to use the first row as the header + quoting: false + quote_char: '"' + double_quote: true + escape_char: '\' + escaping: false + block_size: 4MB + batch_reader: true + null_values: [""] + +vertex_mappings: + - type_name: person # must align with the schema + inputs: + - person.csv +edge_mappings: + - type_triplet: + edge: knows + source_vertex: person + destination_vertex: person + inputs: + - knows.csv + source_vertex_mappings: + - column: + index: 0 + name: source_person_id + destination_vertex_mappings: + - column: + index: 1 + name: destination_person_id + \ No newline at end of file From f0f451d4ae8318238c4041709527a33f3f355051 Mon Sep 17 00:00:00 2001 From: shirly121 Date: Mon, 10 Mar 2025 16:06:47 +0800 Subject: [PATCH 15/17] minor fix to interactive_config_test.yaml --- flex/tests/hqps/interactive_config_test.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/flex/tests/hqps/interactive_config_test.yaml b/flex/tests/hqps/interactive_config_test.yaml index b27f35e45e13..b318d95dcb67 100644 --- a/flex/tests/hqps/interactive_config_test.yaml +++ b/flex/tests/hqps/interactive_config_test.yaml @@ -12,13 +12,17 @@ compute_engine: type: file # file/sqlite/etcd wal_uri: file://{GRAPH_DATA_DIR}/wal # Could be file://{GRAPH_DATA_DIR}/wal or other supported storage class. GRAPH_DATA_DIR is the placeholder for the graph data directory. compiler: + physical: + opt: + config: proto planner: is_on: true - opt: RBO + opt: CBO rules: - FilterIntoJoinRule - FilterMatchRule - - NotMatchToAntiJoinRule + - ExtendIntersectRule + - ExpandGetVFusionRule meta: reader: schema: From f5716ccec7235d26b99f1cf8e8bc1d7abf95f5f7 Mon Sep 17 00:00:00 2001 From: shirly121 Date: Fri, 14 Mar 2025 17:20:01 +0800 Subject: [PATCH 16/17] fix comparison between float values --- .../integration/flex/bench/FlexTypeTest.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java index 514a38e42308..bf8f4ae721a2 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java @@ -37,6 +37,8 @@ public class FlexTypeTest { private static final Logger logger = LoggerFactory.getLogger(FlexTypeTest.class); private static Session session; + private static final double DOUBLE_DELTA = 1e-15; + private static final float FLOAT_DELTA = 1e-6f; /** * start compiler before the test: @@ -160,8 +162,16 @@ private void checkResult(Supplier resultSupplier, QueryContext ctx) { if (upperCase.endsWith("L") || upperCase.endsWith("D") || upperCase.endsWith("F")) { expectedValue = expectedValue.substring(0, expectedValue.length() - 1); } - String actualValue = getActualValue(actual, unsigned, int32); - Assert.assertEquals(expectedValue, actualValue); + if (upperCase.endsWith("F")) { + Assert.assertEquals( + Float.parseFloat(expectedValue), actual.asFloat(), FLOAT_DELTA); + } else if (upperCase.endsWith("D")) { + Assert.assertEquals( + Double.parseDouble(expectedValue), actual.asDouble(), DOUBLE_DELTA); + } else { + String actualValue = getActualValue(actual, unsigned, int32); + Assert.assertEquals(expectedValue, actualValue); + } } } } From 0f10d27694eab4f465896911c21b8da6b6b2c4e9 Mon Sep 17 00:00:00 2001 From: shirly121 Date: Fri, 14 Mar 2025 17:55:21 +0800 Subject: [PATCH 17/17] set double delta to 0.01 --- .../cypher/integration/flex/bench/FlexTypeTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java index bf8f4ae721a2..dbf4a27aeb27 100644 --- a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java +++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/flex/bench/FlexTypeTest.java @@ -37,8 +37,8 @@ public class FlexTypeTest { private static final Logger logger = LoggerFactory.getLogger(FlexTypeTest.class); private static Session session; - private static final double DOUBLE_DELTA = 1e-15; - private static final float FLOAT_DELTA = 1e-6f; + private static double DOUBLE_DELTA; + private static float FLOAT_DELTA; /** * start compiler before the test: @@ -49,6 +49,8 @@ public static void setUp() { String neo4jServerUrl = System.getProperty("neo4j.bolt.server.url", "neo4j://localhost:7687"); session = GraphDatabase.driver(neo4jServerUrl).session(); + DOUBLE_DELTA = Double.parseDouble(System.getProperty("double.delta", "0.01")); + FLOAT_DELTA = Float.parseFloat(System.getProperty("float.delta", "0.01")); } @Test