Skip to content

Commit 801ac7f

Browse files
authored
branch-3.1: [fix](nereids) fix cast ipv4 to string #51546 (#51981)
cherry pick from #51546
1 parent 5810607 commit 801ac7f

5 files changed

Lines changed: 158 additions & 7 deletions

File tree

fe/fe-core/src/main/java/org/apache/doris/common/util/NetUtils.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import java.io.IOException;
2828
import java.net.DatagramSocket;
29+
import java.net.Inet4Address;
2930
import java.net.InetAddress;
3031
import java.net.InetSocketAddress;
3132
import java.net.NetworkInterface;
@@ -161,4 +162,31 @@ public static SystemInfoService.HostInfo resolveHostInfoFromHostPort(String host
161162
return new SystemInfoService.HostInfo(pair[0], Integer.valueOf(pair[1]));
162163
}
163164

165+
/**
166+
* Convert IPv4 address to long
167+
* @param inet4Address IPv4 address
168+
* @return The corresponding long value
169+
*/
170+
public static long inet4AddressToLong(Inet4Address inet4Address) {
171+
byte[] bytes = inet4Address.getAddress();
172+
long result = 0;
173+
for (byte b : bytes) {
174+
result = result << 8 | (b & 0xFF);
175+
}
176+
return result;
177+
}
178+
179+
/**
180+
* Convert long value back to IPv4 address
181+
* @param value IP address as a long value
182+
* @return The corresponding IPv4 address
183+
*/
184+
public static Inet4Address longToInet4Address(long value) throws Exception {
185+
byte[] bytes = new byte[4];
186+
bytes[0] = (byte) ((value >> 24) & 0xFF);
187+
bytes[1] = (byte) ((value >> 16) & 0xFF);
188+
bytes[2] = (byte) ((value >> 8) & 0xFF);
189+
bytes[3] = (byte) (value & 0xFF);
190+
return (Inet4Address) Inet4Address.getByAddress(bytes);
191+
}
164192
}

fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/IPv4Literal.java

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@
1818
package org.apache.doris.nereids.trees.expressions.literal;
1919

2020
import org.apache.doris.analysis.LiteralExpr;
21+
import org.apache.doris.common.util.NetUtils;
2122
import org.apache.doris.nereids.exceptions.AnalysisException;
2223
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
2324
import org.apache.doris.nereids.types.IPv4Type;
2425

26+
import java.net.Inet4Address;
27+
import java.util.Objects;
2528
import java.util.regex.Pattern;
2629

2730
/**
@@ -32,20 +35,67 @@ public class IPv4Literal extends Literal {
3235
private static final Pattern IPV4_STD_REGEX =
3336
Pattern.compile("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
3437

35-
private long value;
38+
/**
39+
* Add a class Inet4Addr wrap in Inet4Address,
40+
* When cast ipv4 literal to string, it will call `new StringLiteral(ipv4Literal.getValue().toString())`,
41+
* but Inet4Address.toString() contains a prefix "/", like "/192.168.1.10".
42+
* Use Inet4Addr can solve this problem.
43+
*/
44+
public static class Inet4Addr {
45+
final Inet4Address address;
46+
47+
public Inet4Addr(Inet4Address addr) {
48+
this.address = addr;
49+
}
50+
51+
public Inet4Address getAddress() {
52+
return this.address;
53+
}
54+
55+
public long toLong() {
56+
return NetUtils.inet4AddressToLong(address);
57+
}
58+
59+
@Override
60+
public String toString() {
61+
return address.getHostAddress();
62+
}
63+
64+
@Override
65+
public int hashCode() {
66+
return Objects.hash(address);
67+
}
68+
69+
@Override
70+
public boolean equals(Object other) {
71+
if (!(other instanceof Inet4Addr)) {
72+
return false;
73+
}
74+
Inet4Addr otherAddr = (Inet4Addr) other;
75+
return address.equals(otherAddr.address);
76+
}
77+
}
78+
79+
private Inet4Addr value;
3680

3781
public IPv4Literal(String ipv4) throws AnalysisException {
3882
super(IPv4Type.INSTANCE);
3983
init(ipv4);
4084
}
4185

42-
protected IPv4Literal(long value) {
86+
protected IPv4Literal(long value) throws AnalysisException {
4387
super(IPv4Type.INSTANCE);
44-
this.value = value;
88+
Inet4Address address;
89+
try {
90+
address = NetUtils.longToInet4Address(value);
91+
} catch (Exception e) {
92+
throw new AnalysisException(e.getMessage());
93+
}
94+
this.value = new Inet4Addr(address);
4595
}
4696

4797
@Override
48-
public Long getValue() {
98+
public Inet4Addr getValue() {
4999
return value;
50100
}
51101

@@ -56,7 +106,7 @@ public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
56106

57107
@Override
58108
public LiteralExpr toLegacyLiteral() {
59-
return new org.apache.doris.analysis.IPv4Literal(value);
109+
return new org.apache.doris.analysis.IPv4Literal(value.toLong());
60110
}
61111

62112
void init(String ipv4) throws AnalysisException {
@@ -80,7 +130,13 @@ void init(String ipv4) throws AnalysisException {
80130
}
81131
value = (value << 8) | octet;
82132
}
83-
this.value = value;
133+
Inet4Address address;
134+
try {
135+
address = NetUtils.longToInet4Address(value);
136+
} catch (Exception e) {
137+
throw new AnalysisException(e.getMessage());
138+
}
139+
this.value = new Inet4Addr(address);
84140
}
85141

86142
private void checkValueValid(String ipv4) throws AnalysisException {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.apache.doris.common.util;
19+
20+
import org.junit.Assert;
21+
import org.junit.Test;
22+
23+
import java.net.Inet4Address;
24+
import java.net.InetAddress;
25+
26+
public class NetUtilsTest {
27+
28+
@Test
29+
public void testConvertIp() throws Exception {
30+
long ipValue = 3232235786L;
31+
InetAddress ip = InetAddress.getByName("192.168.1.10");
32+
Assert.assertTrue(ip instanceof Inet4Address);
33+
Assert.assertEquals(ipValue, NetUtils.inet4AddressToLong((Inet4Address) ip));
34+
Inet4Address convertIp = NetUtils.longToInet4Address(ipValue);
35+
Assert.assertEquals(ip, convertIp);
36+
}
37+
}

regression-test/data/nereids_rules_p0/infer_predicate/pull_up_predicate_literal.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2471,7 +2471,7 @@ PhysicalResultSink
24712471
----------PhysicalProject
24722472
------------PhysicalStorageLayerAggregate[test_pull_up_predicate_literal]
24732473
------PhysicalProject
2474-
--------filter((t2.d_ipv4 = 2130706433))
2474+
--------filter((t2.d_ipv4 = 127.0.0.1))
24752475
----------PhysicalOlapScan[test_types]
24762476

24772477
-- !const_value_and_join_column_type239 --
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
suite("fold_constant_ip") {
19+
// cast function
20+
for (def ipv4 : ["1", "256.256.256.256", "192.168.1.10"]) {
21+
testFoldConst("SELECT cast('${ipv4}' as ipv4)")
22+
testFoldConst("SELECT cast(cast('${ipv4}' as ipv4) as string)")
23+
testFoldConst("SELECT cast(cast(cast('${ipv4}' as ipv4) as string) as ipv4)")
24+
}
25+
for (def ipv6 : ["1", "ef8d:3d6a:869b:2582:7200:aa46:4dcd:2bd4"]) {
26+
testFoldConst("SELECT cast('${ipv6}' as ipv6)")
27+
testFoldConst("SELECT cast(cast('${ipv6}' as ipv6) as string)")
28+
testFoldConst("SELECT cast(cast(cast('${ipv6}' as ipv6) as string) as ipv6)")
29+
}
30+
}

0 commit comments

Comments
 (0)