Skip to content

Commit 218cf1f

Browse files
committed
fixed ip address conversion
1 parent afc6ada commit 218cf1f

File tree

6 files changed

+117
-10
lines changed

6 files changed

+117
-10
lines changed

client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/AbstractBinaryFormatReader.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.math.BigInteger;
2929
import java.net.Inet4Address;
3030
import java.net.Inet6Address;
31+
import java.net.InetAddress;
3132
import java.time.Duration;
3233
import java.time.Instant;
3334
import java.time.LocalDate;
@@ -486,12 +487,12 @@ public TemporalAmount getTemporalAmount(String colName) {
486487

487488
@Override
488489
public Inet4Address getInet4Address(String colName) {
489-
return readValue(colName);
490+
return InetAddressConverter.convertToIpv4(readValue(colName));
490491
}
491492

492493
@Override
493494
public Inet6Address getInet6Address(String colName) {
494-
return readValue(colName);
495+
return InetAddressConverter.convertToIpv6(readValue(colName));
495496
}
496497

497498
@Override
@@ -651,12 +652,12 @@ public TemporalAmount getTemporalAmount(int index) {
651652

652653
@Override
653654
public Inet4Address getInet4Address(int index) {
654-
return readValue(index);
655+
return InetAddressConverter.convertToIpv4(readValue(index));
655656
}
656657

657658
@Override
658659
public Inet6Address getInet6Address(int index) {
659-
return readValue(index);
660+
return InetAddressConverter.convertToIpv6(readValue(index));
660661
}
661662

662663
@Override
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.clickhouse.client.api.data_formats.internal;
2+
3+
import java.net.Inet4Address;
4+
import java.net.Inet6Address;
5+
import java.net.InetAddress;
6+
import java.net.UnknownHostException;
7+
8+
public class InetAddressConverter {
9+
10+
/**
11+
* Converts IPv4 address to IPv6 address.
12+
*
13+
* @param value IPv4 address
14+
* @return IPv6 address
15+
* @throws IllegalArgumentException when failed to convert to IPv6 address
16+
*/
17+
public static Inet6Address convertToIpv6(InetAddress value) {
18+
if (value == null || value instanceof Inet6Address) {
19+
return (Inet6Address) value;
20+
}
21+
22+
// https://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses
23+
byte[] bytes = new byte[16];
24+
bytes[10] = (byte) 0xFF;
25+
bytes[11] = (byte) 0xFF;
26+
System.arraycopy(value.getAddress(), 0, bytes, 12, 4);
27+
28+
try {
29+
return Inet6Address.getByAddress(null, bytes, null);
30+
} catch (UnknownHostException e) {
31+
throw new IllegalArgumentException(e);
32+
}
33+
}
34+
35+
/**
36+
* Converts IPv6 address to IPv4 address if applicable.
37+
*
38+
* @param value IPv6 address
39+
* @return IPv4 address
40+
* @throws IllegalArgumentException when failed to convert to IPv4 address
41+
*/
42+
public static Inet4Address convertToIpv4(InetAddress value) {
43+
if (value == null || value instanceof Inet4Address) {
44+
return (Inet4Address) value;
45+
}
46+
47+
byte[] bytes = value.getAddress();
48+
boolean invalid = false;
49+
for (int i = 0; i < 10; i++) {
50+
if (bytes[i] != (byte) 0) {
51+
invalid = true;
52+
break;
53+
}
54+
}
55+
56+
if (!invalid) {
57+
invalid = bytes[10] != 0xFF || bytes[11] != 0xFF;
58+
}
59+
60+
if (invalid) {
61+
throw new IllegalArgumentException("Failed to convert IPv6 to IPv4");
62+
}
63+
64+
byte[] addr = new byte[4];
65+
System.arraycopy(bytes, 12, addr, 0, 4);
66+
try {
67+
return (Inet4Address) InetAddress.getByAddress(addr);
68+
} catch (UnknownHostException e) {
69+
throw new IllegalArgumentException(e);
70+
}
71+
}
72+
}

client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/MapBackedRecord.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,12 @@ public TemporalAmount getTemporalAmount(String colName) {
162162

163163
@Override
164164
public Inet4Address getInet4Address(String colName) {
165-
return readValue(colName);
165+
return InetAddressConverter.convertToIpv4(readValue(colName));
166166
}
167167

168168
@Override
169169
public Inet6Address getInet6Address(String colName) {
170-
return readValue(colName);
170+
return InetAddressConverter.convertToIpv6(readValue(colName));
171171
}
172172

173173
@Override
@@ -323,12 +323,12 @@ public TemporalAmount getTemporalAmount(int index) {
323323

324324
@Override
325325
public Inet4Address getInet4Address(int index) {
326-
return readValue(index);
326+
return InetAddressConverter.convertToIpv4(readValue(index));
327327
}
328328

329329
@Override
330330
public Inet6Address getInet6Address(int index) {
331-
return readValue(index);
331+
return InetAddressConverter.convertToIpv6(readValue(index));
332332
}
333333

334334
@Override

client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/SerializerUtils.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import java.math.BigInteger;
2929
import java.net.Inet4Address;
3030
import java.net.Inet6Address;
31+
import java.net.InetAddress;
32+
import java.net.UnknownHostException;
3133
import java.sql.Timestamp;
3234
import java.time.*;
3335
import java.time.temporal.TemporalUnit;

client-v2/src/test/java/com/clickhouse/client/query/QueryTests.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.testng.annotations.Test;
4545
import org.testng.util.Strings;
4646

47+
import javax.management.Query;
4748
import java.io.BufferedReader;
4849
import java.io.BufferedWriter;
4950
import java.io.ByteArrayInputStream;
@@ -781,7 +782,34 @@ public void testIPAddresses() throws Exception {
781782
testDataTypes(columns, valueGenerators, verifiers);
782783
}
783784

784-
@Test
785+
@Test(groups = {"integration"})
786+
public void testConversionOfIpAddresses() throws Exception {
787+
788+
try (QueryResponse response = client.query("SELECT toIPv6('::ffff:90.176.75.97') ipv4, toIPv6('2001:db8:85a3::8a2e:370:7334') ipv6").get()) {
789+
ClickHouseBinaryFormatReader reader = client.newBinaryFormatReader(response);
790+
791+
reader.next();
792+
InetAddress ipv4 = reader.getInet4Address(1);
793+
Assert.assertNotNull(ipv4);
794+
InetAddress ipv6 = reader.getInet6Address(2);
795+
Assert.assertNotNull(ipv6);
796+
InetAddress ipv4_as_ipv6 = reader.getInet6Address(1);
797+
Assert.assertEquals(Inet4Address.getByAddress(ipv4_as_ipv6.getAddress()), ipv4);
798+
Assert.assertThrows(() -> reader.getInet4Address(2));
799+
}
800+
801+
List<GenericRecord> records = client.queryAll("SELECT toIPv6('::ffff:90.176.75.97') ipv4, toIPv6('2001:db8:85a3::8a2e:370:7334') ipv6");
802+
GenericRecord record = records.get(0);
803+
InetAddress ipv4 = record.getInet4Address(1);
804+
Assert.assertNotNull(ipv4);
805+
InetAddress ipv6 = record.getInet6Address(2);
806+
Assert.assertNotNull(ipv6);
807+
InetAddress ipv4_as_ipv6 = record.getInet6Address(1);
808+
Assert.assertEquals(Inet4Address.getByAddress(ipv4_as_ipv6.getAddress()), ipv4);
809+
Assert.assertThrows(() -> record.getInet4Address(2));
810+
}
811+
812+
@Test(groups = {"integration"})
785813
public void testDateTimeDataTypes() {
786814
final List<String> columns = Arrays.asList(
787815
"min_date Date",

jdbc-v2/src/test/java/com/clickhouse/jdbc/DataTypeTests.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ public void testStringTypes() throws SQLException {
519519
@Test(groups = { "integration" })
520520
public void testIpAddressTypes() throws SQLException, UnknownHostException {
521521
runQuery("CREATE TABLE test_ips (order Int8, "
522-
+ "ipv4_ip IPv4, ipv4_name IPv4, ipv6 IPv6"
522+
+ "ipv4_ip IPv4, ipv4_name IPv4, ipv6 IPv6, ipv4_as_ipv6 IPv6"
523523
+ ") ENGINE = MergeTree ORDER BY ()");
524524

525525
// Insert random (valid) values
@@ -529,12 +529,14 @@ public void testIpAddressTypes() throws SQLException, UnknownHostException {
529529
InetAddress ipv4AddressByIp = Inet4Address.getByName(rand.nextInt(256) + "." + rand.nextInt(256) + "." + rand.nextInt(256) + "." + rand.nextInt(256));
530530
InetAddress ipv4AddressByName = Inet4Address.getByName("www.example.com");
531531
InetAddress ipv6Address = Inet6Address.getByName("2001:adb8:85a3:1:2:8a2e:370:7334");
532+
InetAddress ipv4AsIpv6 = Inet4Address.getByName("90.176.75.97");
532533

533534
try (Connection conn = getConnection()) {
534535
try (PreparedStatement stmt = conn.prepareStatement("INSERT INTO test_ips VALUES ( 1, ?, ?, ? )")) {
535536
stmt.setObject(1, ipv4AddressByIp);
536537
stmt.setObject(2, ipv4AddressByName);
537538
stmt.setObject(3, ipv6Address);
539+
stmt.setObject(4, ipv4AsIpv6);
538540
stmt.executeUpdate();
539541
}
540542
}
@@ -549,6 +551,8 @@ public void testIpAddressTypes() throws SQLException, UnknownHostException {
549551
assertEquals(rs.getObject("ipv4_name"), ipv4AddressByName);
550552
assertEquals(rs.getObject("ipv6"), ipv6Address);
551553
assertEquals(rs.getString("ipv6"), ipv6Address.toString());
554+
String value = rs.getObject("ipv4_as_ipv6").toString();
555+
System.out.println("ip: " + value);
552556
assertFalse(rs.next());
553557
}
554558
}

0 commit comments

Comments
 (0)