Skip to content

Commit 755b5d0

Browse files
tsegismontAyanKoche
authored andcommitted
Added Cidr data type support in pgclient
1 parent acb02de commit 755b5d0

File tree

5 files changed

+183
-2
lines changed

5 files changed

+183
-2
lines changed

vertx-pg-client/README.adoc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,10 @@ The *Reactive Postgres Client* currently supports the following data types
221221
|`io.vertx.pgclient.data.Money[]`
222222
|✔
223223

224+
|`CIDR`
225+
|`io.vertx.pgclient.data.Cidr`
226+
|✔
227+
224228
|`PATH`
225229
|`i.r.p.data.Path`
226230
|✔
@@ -270,7 +274,7 @@ Note: PostgreSQL JSON and JSONB types are represented by the following Java type
270274

271275
The following types
272276

273-
_MONEY_, _BIT_, _VARBIT_, _MACADDR_, _CIDR_, _MACADDR8_,
277+
_MONEY_, _BIT_, _VARBIT_, _MACADDR_, _MACADDR8_,
274278
_XML_, _HSTORE_, _OID_,
275279
_VOID_
276280

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package io.vertx.pgclient.data;
2+
3+
import java.net.Inet4Address;
4+
import java.net.Inet6Address;
5+
import java.net.InetAddress;
6+
7+
/**
8+
* A PostgreSQL <a href="https://www.postgresql.org/docs/current/datatype-net-types.html#DATATYPE-CIDR">classless internet domain routing</a>.
9+
*/
10+
public class Cidr {
11+
private InetAddress address;
12+
private Integer netmask;
13+
14+
public InetAddress getAddress(){
15+
return address;
16+
}
17+
public Cidr setAddress(InetAddress address) {
18+
if (address instanceof Inet4Address || address instanceof Inet6Address) {
19+
this.address = address;
20+
} else {
21+
throw new IllegalArgumentException("Invalid IP address type");
22+
}
23+
return this;
24+
}
25+
26+
public Integer getNetmask(){
27+
return netmask;
28+
}
29+
30+
public Cidr setNetmask(Integer netmask) {
31+
if (netmask != null && ((getAddress() instanceof Inet4Address && (netmask < 0 || netmask > 32)) ||
32+
(getAddress() instanceof Inet6Address && (netmask < 0 || netmask > 128)))) {
33+
throw new IllegalArgumentException("Invalid netmask: " + netmask);
34+
}
35+
this.netmask = netmask;
36+
return this;
37+
}
38+
39+
40+
}

vertx-pg-client/src/main/java/io/vertx/pgclient/impl/codec/DataType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import io.vertx.pgclient.data.Line;
2929
import io.vertx.pgclient.data.LineSegment;
3030
import io.vertx.pgclient.data.Money;
31+
import io.vertx.pgclient.data.Cidr;
3132
import io.vertx.sqlclient.Tuple;
3233
import io.vertx.sqlclient.data.Numeric;
3334
import io.vertx.pgclient.data.Interval;
@@ -97,7 +98,7 @@ public enum DataType {
9798
MACADDR(829, true, Object.class, JDBCType.OTHER),
9899
INET(869, true, Inet.class, JDBCType.OTHER),
99100
INET_ARRAY(1041, true, Inet[].class, JDBCType.OTHER),
100-
CIDR(650, true, Object.class, JDBCType.OTHER),
101+
CIDR(650, true, Cidr.class, JDBCType.OTHER),
101102
MACADDR8(774, true, Object[].class, JDBCType.OTHER),
102103
UUID(2950, true, UUID.class, JDBCType.OTHER, Tuple::getUUID),
103104
UUID_ARRAY(2951, true, UUID[].class, JDBCType.OTHER, Tuple::getArrayOfUUIDs),

vertx-pg-client/src/main/java/io/vertx/pgclient/impl/codec/DataTypeCodec.java

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,9 @@ public static void encodeBinary(DataType id, Object value, ByteBuf buff) {
364364
case MONEY_ARRAY:
365365
binaryEncodeArray((Money[]) value, DataType.MONEY, buff);
366366
break;
367+
case CIDR:
368+
binaryEncodeCidr((Cidr) value, buff);
369+
break;
367370
default:
368371
logger.debug("Data type " + id + " does not support binary encoding");
369372
defaultEncodeBinary(value, buff);
@@ -501,6 +504,8 @@ public static Object decodeBinary(DataType id, int index, int len, ByteBuf buff)
501504
return binaryDecodeMoney(index, len, buff);
502505
case MONEY_ARRAY:
503506
return binaryDecodeArray(MONEY_ARRAY_FACTORY, DataType.MONEY, index, len, buff);
507+
case CIDR:
508+
return binaryDecodeCidr(index, len, buff);
504509
default:
505510
logger.debug("Data type " + id + " does not support binary decoding");
506511
return defaultDecodeBinary(index, len, buff);
@@ -641,6 +646,8 @@ public static Object decodeText(DataType id, int index, int len, ByteBuf buff) {
641646
return textDecodeMoney(index, len, buff);
642647
case MONEY_ARRAY:
643648
return textDecodeArray(MONEY_ARRAY_FACTORY, DataType.MONEY, index, len, buff);
649+
case CIDR:
650+
return textDecodeCidr(index, len, buff);
644651
default:
645652
return defaultDecodeText(index, len, buff);
646653
}
@@ -1713,4 +1720,85 @@ private static <T> void textEncodeArray(T[] values, DataType type, ByteBuf buff)
17131720
}
17141721
buff.writeByte('}');
17151722
}
1723+
1724+
private static Cidr binaryDecodeCidr(int index, int len, ByteBuf buff){
1725+
byte family = buff.getByte(index);
1726+
byte netmask = buff.getByte(index+1);
1727+
Integer val;
1728+
int size = buff.getByte(index+3);
1729+
byte[] data = new byte[size];
1730+
buff.getBytes(index+4,data);
1731+
InetAddress address;
1732+
1733+
switch (family){
1734+
case 2:
1735+
case 3:
1736+
// IPV4 and IPV6
1737+
try {
1738+
address = InetAddress.getByAddress(data);
1739+
}catch (UnknownHostException e){
1740+
throw new DecoderException(e);
1741+
}
1742+
break;
1743+
default:
1744+
throw new DecoderException("Invalid IP family: " + family);
1745+
}
1746+
val = Byte.toUnsignedInt(netmask);
1747+
return new Cidr().setAddress(address).setNetmask(val);
1748+
}
1749+
1750+
private static void binaryEncodeCidr(Cidr value, ByteBuf buff) {
1751+
InetAddress address = value.getAddress();
1752+
byte family;
1753+
byte[] data;
1754+
int netmask;
1755+
1756+
if (address instanceof Inet6Address) {
1757+
family = 3;
1758+
Inet6Address inet6Address = (Inet6Address) address;
1759+
data = inet6Address.getAddress();
1760+
netmask = (value.getNetmask() == null) ? 128 : value.getNetmask();
1761+
} else if (address instanceof Inet4Address) {
1762+
family = 2;
1763+
Inet4Address inet4Address = (Inet4Address) address;
1764+
data = inet4Address.getAddress();
1765+
netmask = (value.getNetmask() == null) ? 32 : value.getNetmask();
1766+
} else {
1767+
throw new DecoderException("Invalid inet address");
1768+
}
1769+
1770+
buff.writeByte(family);
1771+
buff.writeByte(netmask);
1772+
buff.writeByte(0); // INET
1773+
buff.writeByte(data.length);
1774+
buff.writeBytes(data);
1775+
}
1776+
1777+
private static Cidr textDecodeCidr(int index, int len, ByteBuf buff) {
1778+
Cidr cidr = new Cidr();
1779+
int sepIdx = buff.indexOf(index, index + len, (byte) '/');
1780+
String s;
1781+
1782+
if (sepIdx == -1) {
1783+
s = textdecodeTEXT(index, len, buff);
1784+
} else {
1785+
s = textdecodeTEXT(index, sepIdx - index, buff);
1786+
String t = textdecodeTEXT(sepIdx + 1, len - (sepIdx + 1 - index), buff);
1787+
try {
1788+
int netmask = Integer.parseInt(t);
1789+
cidr.setNetmask(netmask);
1790+
} catch (NumberFormatException e) {
1791+
throw new DecoderException(e);
1792+
}
1793+
}
1794+
1795+
try {
1796+
InetAddress v = InetAddress.getByName(s);
1797+
cidr.setAddress(v);
1798+
} catch (UnknownHostException e) {
1799+
throw new DecoderException(e);
1800+
}
1801+
1802+
return cidr;
1803+
}
17161804
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package io.vertx.pgclient.data;
2+
3+
import org.junit.Test;
4+
5+
import java.net.InetAddress;
6+
7+
import static org.junit.Assert.assertEquals;
8+
import static org.junit.Assert.assertThrows;
9+
10+
public class CidrTest extends DataTypeTestBase{
11+
12+
@Test
13+
public void testValidIPv4() throws Exception {
14+
InetAddress address = InetAddress.getByName("192.168.1.1");
15+
Cidr cidr = new Cidr();
16+
cidr.setAddress(address);
17+
cidr.setNetmask(24);
18+
assertEquals(address, cidr.getAddress());
19+
assertEquals(Integer.valueOf(24), cidr.getNetmask());
20+
}
21+
22+
@Test
23+
public void testValidIPv6() throws Exception {
24+
InetAddress address = InetAddress.getByName("fe80::f03c:91ff:feae:e944");
25+
Cidr cidr = new Cidr();
26+
cidr.setAddress(address);
27+
cidr.setNetmask(64);
28+
assertEquals(address, cidr.getAddress());
29+
assertEquals(Integer.valueOf(64), cidr.getNetmask());
30+
}
31+
32+
@Test
33+
public void testInvalidNetmaskIPv4() throws Exception {
34+
InetAddress address = InetAddress.getByName("192.168.1.1");
35+
Cidr cidr = new Cidr();
36+
cidr.setAddress(address);
37+
assertThrows(IllegalArgumentException.class, () -> cidr.setNetmask(33));
38+
}
39+
40+
@Test
41+
public void testInvalidNetmaskIPv6() throws Exception {
42+
InetAddress address = InetAddress.getByName("fe80::f03c:91ff:feae:e944");
43+
Cidr cidr = new Cidr();
44+
cidr.setAddress(address);
45+
assertThrows(IllegalArgumentException.class, () -> cidr.setNetmask(129));
46+
}
47+
48+
}

0 commit comments

Comments
 (0)