branch-2.1: [fix](nereids) fix cast ipv4 to string #51546 (#51738)

cherry pick from #51546
This commit is contained in:
yujun
2025-06-16 15:45:39 +08:00
committed by GitHub
parent c6ff4994f3
commit eaa6556721
5 changed files with 158 additions and 7 deletions

View File

@ -26,6 +26,7 @@ import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
@ -161,4 +162,31 @@ public class NetUtils {
return new SystemInfoService.HostInfo(pair[0], Integer.valueOf(pair[1]));
}
/**
* Convert IPv4 address to long
* @param inet4Address IPv4 address
* @return The corresponding long value
*/
public static long inet4AddressToLong(Inet4Address inet4Address) {
byte[] bytes = inet4Address.getAddress();
long result = 0;
for (byte b : bytes) {
result = result << 8 | (b & 0xFF);
}
return result;
}
/**
* Convert long value back to IPv4 address
* @param value IP address as a long value
* @return The corresponding IPv4 address
*/
public static Inet4Address longToInet4Address(long value) throws Exception {
byte[] bytes = new byte[4];
bytes[0] = (byte) ((value >> 24) & 0xFF);
bytes[1] = (byte) ((value >> 16) & 0xFF);
bytes[2] = (byte) ((value >> 8) & 0xFF);
bytes[3] = (byte) (value & 0xFF);
return (Inet4Address) Inet4Address.getByAddress(bytes);
}
}

View File

@ -18,10 +18,13 @@
package org.apache.doris.nereids.trees.expressions.literal;
import org.apache.doris.analysis.LiteralExpr;
import org.apache.doris.common.util.NetUtils;
import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.IPv4Type;
import java.net.Inet4Address;
import java.util.Objects;
import java.util.regex.Pattern;
/**
@ -32,20 +35,67 @@ public class IPv4Literal extends Literal {
private static final Pattern IPV4_STD_REGEX =
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]?)$");
private long value;
/**
* Add a class Inet4Addr wrap in Inet4Address,
* When cast ipv4 literal to string, it will call `new StringLiteral(ipv4Literal.getValue().toString())`,
* but Inet4Address.toString() contains a prefix "/", like "/192.168.1.10".
* Use Inet4Addr can solve this problem.
*/
public static class Inet4Addr {
final Inet4Address address;
public Inet4Addr(Inet4Address addr) {
this.address = addr;
}
public Inet4Address getAddress() {
return this.address;
}
public long toLong() {
return NetUtils.inet4AddressToLong(address);
}
@Override
public String toString() {
return address.getHostAddress();
}
@Override
public int hashCode() {
return Objects.hash(address);
}
@Override
public boolean equals(Object other) {
if (!(other instanceof Inet4Addr)) {
return false;
}
Inet4Addr otherAddr = (Inet4Addr) other;
return address.equals(otherAddr.address);
}
}
private Inet4Addr value;
public IPv4Literal(String ipv4) throws AnalysisException {
super(IPv4Type.INSTANCE);
init(ipv4);
}
protected IPv4Literal(long value) {
protected IPv4Literal(long value) throws AnalysisException {
super(IPv4Type.INSTANCE);
this.value = value;
Inet4Address address;
try {
address = NetUtils.longToInet4Address(value);
} catch (Exception e) {
throw new AnalysisException(e.getMessage());
}
this.value = new Inet4Addr(address);
}
@Override
public Long getValue() {
public Inet4Addr getValue() {
return value;
}
@ -56,7 +106,7 @@ public class IPv4Literal extends Literal {
@Override
public LiteralExpr toLegacyLiteral() {
return new org.apache.doris.analysis.IPv4Literal(value);
return new org.apache.doris.analysis.IPv4Literal(value.toLong());
}
void init(String ipv4) throws AnalysisException {
@ -80,7 +130,13 @@ public class IPv4Literal extends Literal {
}
value = (value << 8) | octet;
}
this.value = value;
Inet4Address address;
try {
address = NetUtils.longToInet4Address(value);
} catch (Exception e) {
throw new AnalysisException(e.getMessage());
}
this.value = new Inet4Addr(address);
}
private void checkValueValid(String ipv4) throws AnalysisException {

View File

@ -0,0 +1,37 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 org.apache.doris.common.util;
import org.junit.Assert;
import org.junit.Test;
import java.net.Inet4Address;
import java.net.InetAddress;
public class NetUtilsTest {
@Test
public void testConvertIp() throws Exception {
long ipValue = 3232235786L;
InetAddress ip = InetAddress.getByName("192.168.1.10");
Assert.assertTrue(ip instanceof Inet4Address);
Assert.assertEquals(ipValue, NetUtils.inet4AddressToLong((Inet4Address) ip));
Inet4Address convertIp = NetUtils.longToInet4Address(ipValue);
Assert.assertEquals(ip, convertIp);
}
}

View File

@ -2016,7 +2016,7 @@ PhysicalResultSink
----------PhysicalProject
------------PhysicalOlapScan[test_pull_up_predicate_literal]
------PhysicalProject
--------filter((t2.d_ipv4 = 2130706433))
--------filter((t2.d_ipv4 = 127.0.0.1))
----------PhysicalOlapScan[test_types]
-- !const_value_and_join_column_type239 --

View File

@ -0,0 +1,30 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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.
suite("fold_constant_ip") {
// cast function
for (def ipv4 : ["1", "256.256.256.256", "192.168.1.10"]) {
testFoldConst("SELECT cast('${ipv4}' as ipv4)")
testFoldConst("SELECT cast(cast('${ipv4}' as ipv4) as string)")
testFoldConst("SELECT cast(cast(cast('${ipv4}' as ipv4) as string) as ipv4)")
}
for (def ipv6 : ["1", "ef8d:3d6a:869b:2582:7200:aa46:4dcd:2bd4"]) {
testFoldConst("SELECT cast('${ipv6}' as ipv6)")
testFoldConst("SELECT cast(cast('${ipv6}' as ipv6) as string)")
testFoldConst("SELECT cast(cast(cast('${ipv6}' as ipv6) as string) as ipv6)")
}
}