From 494dd626996f17578c91585b878c2e4ae448442d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 2 Dec 2025 00:46:18 +0000 Subject: [PATCH] Add hashCode() and equals() to the implmentation classes of ExprJavaType (#4885) (cherry picked from commit 96370bfa573831d046db5f5c7029113460cbbb11) Signed-off-by: github-actions[bot] --- .../sql/calcite/type/ExprJavaType.java | 4 +- .../sql/data/model/ExprIpValue.java | 2 + .../rest-api-spec/test/issues/4726.yml | 83 +++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 integ-test/src/yamlRestTest/resources/rest-api-spec/test/issues/4726.yml diff --git a/core/src/main/java/org/opensearch/sql/calcite/type/ExprJavaType.java b/core/src/main/java/org/opensearch/sql/calcite/type/ExprJavaType.java index cbda5974d3c..d9b33902d10 100644 --- a/core/src/main/java/org/opensearch/sql/calcite/type/ExprJavaType.java +++ b/core/src/main/java/org/opensearch/sql/calcite/type/ExprJavaType.java @@ -14,7 +14,9 @@ /** * The JavaType for ExprUDT. The UDT which needs to use self-implemented java class should extend - * this. + * this. Its javaClazz should override equals() and hashCode() methods. For example, {@link + * org.opensearch.sql.data.model.ExprIpValue} (javaClazz of {@link ExprIPType}) overrides the + * equals() and hashCode(). */ public class ExprJavaType extends AbstractExprRelDataType { public ExprJavaType(OpenSearchTypeFactory typeFactory, ExprUDT exprUDT, Class javaClazz) { diff --git a/core/src/main/java/org/opensearch/sql/data/model/ExprIpValue.java b/core/src/main/java/org/opensearch/sql/data/model/ExprIpValue.java index 7723ee8c689..f951db9cf56 100644 --- a/core/src/main/java/org/opensearch/sql/data/model/ExprIpValue.java +++ b/core/src/main/java/org/opensearch/sql/data/model/ExprIpValue.java @@ -6,11 +6,13 @@ package org.opensearch.sql.data.model; import inet.ipaddr.IPAddress; +import lombok.EqualsAndHashCode; import org.opensearch.sql.data.type.ExprCoreType; import org.opensearch.sql.data.type.ExprType; import org.opensearch.sql.utils.IPUtils; /** Expression IP Address Value. */ +@EqualsAndHashCode(callSuper = false) public class ExprIpValue extends AbstractExprValue { private final IPAddress value; diff --git a/integ-test/src/yamlRestTest/resources/rest-api-spec/test/issues/4726.yml b/integ-test/src/yamlRestTest/resources/rest-api-spec/test/issues/4726.yml new file mode 100644 index 00000000000..4e267493da3 --- /dev/null +++ b/integ-test/src/yamlRestTest/resources/rest-api-spec/test/issues/4726.yml @@ -0,0 +1,83 @@ +setup: + - do: + query.settings: + body: + transient: + plugins.calcite.enabled : true + - do: + indices.create: + index: test1 + body: + mappings: + properties: + "timestamp": + type: date + "status": + type: integer + "client_ip": + type: ip + - do: + indices.create: + index: test2 + body: + mappings: + properties: + "client_ip": + type: ip + "city": + type: keyword + "country": + type: keyword + - do: + bulk: + index: test1 + refresh: true + body: + - '{"index":{}}' + - '{"datetime":"2025-01-15T00:30:00Z","status":200,"client_ip":"10.0.0.1"}' + - '{"index":{}}' + - '{"datetime":"2025-01-15T02:15:00Z","status":200,"client_ip":"10.0.0.2"}' + - '{"index":{}}' + - '{"datetime":"2025-01-15T10:50:00Z","status":200,"client_ip":"10.0.0.11"}' + - '{"index":{}}' + - '{"datetime":"2025-01-15T23:45:00Z","status":200,"client_ip":"10.0.0.24"}' + - do: + bulk: + index: test2 + refresh: true + body: + - '{"index":{}}' + - '{"client_ip": "10.0.0.1","country": "Canada","city": "Toronto"}' + - '{"index":{}}' + - '{"client_ip": "10.0.0.24","country": "UK","city": "London"}' + - '{"index":{}}' + - '{"client_ip": "10.0.1.1","country": "USA","city": "New York"}' + - '{"index":{}}' + - '{"client_ip": "10.0.1.2","country": "USA","city": "Seattle"}' + +--- +teardown: + - do: + query.settings: + body: + transient: + plugins.calcite.enabled : false + +--- +"hash join on IP type should work": + - skip: + features: + - headers + - allowed_warnings + - do: + allowed_warnings: + - 'Loading the fielddata on the _id field is deprecated and will be removed in future versions. If you require sorting or aggregating on this field you should also include the id in the body of your documents, and map this field as a keyword field that has [doc_values] enabled' + headers: + Content-Type: 'application/json' + ppl: + body: + query: source=test1 | stats count() as cnt by client_ip | join type=inner client_ip test2 | fields client_ip, cnt + + + - match: { total: 2 } + - match: {"datarows": [["10.0.0.1", 1], ["10.0.0.24", 1]]}