Skip to content

Commit

Permalink
[FEATURE]: Add IPv6 type. #430
Browse files Browse the repository at this point in the history
  • Loading branch information
demetribu committed Oct 8, 2023
1 parent 72ff02f commit 3d25086
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.github.housepower.data.type.DataTypeFloat32;
import com.github.housepower.data.type.DataTypeFloat64;
import com.github.housepower.data.type.DataTypeIPv4;
import com.github.housepower.data.type.DataTypeIPv6;
import com.github.housepower.data.type.DataTypeInt16;
import com.github.housepower.data.type.DataTypeInt32;
import com.github.housepower.data.type.DataTypeInt64;
Expand Down Expand Up @@ -103,6 +104,7 @@ public class DataTypeFactory {
Map<String, IDataType<?, ?>> creators = new HashMap<>();

registerType(creators, new DataTypeIPv4());
registerType(creators, new DataTypeIPv6());
registerType(creators, new DataTypeUUID());
registerType(creators, new DataTypeFloat32());
registerType(creators, new DataTypeFloat64());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Licensed 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 com.github.housepower.data.type;

import com.github.housepower.data.IDataType;
import com.github.housepower.misc.SQLLexer;
import com.github.housepower.serde.BinaryDeserializer;
import com.github.housepower.serde.BinarySerializer;

import java.io.IOException;
import java.math.BigInteger;
import java.sql.SQLException;
import java.sql.Types;

public class DataTypeIPv6 implements IDataType<BigInteger, BigInteger> {

@Override
public String name() {
return "IPv6";
}

@Override
public int sqlTypeId() {
return Types.BIGINT;
}

@Override
public BigInteger defaultValue() {
return BigInteger.ZERO;
}

@Override
public Class<BigInteger> javaType() {
return BigInteger.class;
}

@Override
public int getPrecision() {
return 0;
}

@Override
public int getScale() {
return 39;
}

@Override
public void serializeBinary(BigInteger data, BinarySerializer serializer) throws SQLException, IOException {
byte[] bytes = data.toByteArray();
if (bytes.length > 16) {
throw new SQLException("IPv6 representation exceeds 16 bytes.");
}
byte[] paddedBytes = new byte[16];
int offset = 16 - bytes.length;
System.arraycopy(bytes, 0, paddedBytes, offset, bytes.length);
serializer.writeBytes(paddedBytes, 0, paddedBytes.length);
}

@Override
public BigInteger deserializeBinary(BinaryDeserializer deserializer) throws SQLException, IOException {
byte[] bytes = deserializer.readBytes(16);
return new BigInteger(1, bytes); // force it to be positive
}
@Override
public String[] getAliases() {
return new String[0];
}

@Override
public BigInteger deserializeText(SQLLexer lexer) throws SQLException {
String ipv6String = convertIPv6ToHexadecimalString(lexer.stringLiteral());
return new BigInteger(ipv6String, 16);
}

private static String convertIPv6ToHexadecimalString(String ipv6) {
return ipv6.replace(":", "");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.github.housepower.settings.ClickHouseConfig;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.*;
Expand Down Expand Up @@ -143,6 +144,21 @@ public URL getURL(String name) throws SQLException {
return this.getURL(this.findColumn(name));
}

public BigInteger getBigInteger(String columnName) throws SQLException {
return getBigInteger(findColumn(columnName));
}

public BigInteger getBigInteger(int columnIndex) throws SQLException {
Object valueObj = getObject(columnIndex);
if (valueObj instanceof BigInteger) {
return (BigInteger) valueObj;
}
if (wasNull()) {
return null;
}
throw new SQLException("Column " + columnIndex + " is not of type BigInteger.");
}

@Override
public Array getArray(String name) throws SQLException {
return this.getArray(this.findColumn(name));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
* limitations under the License.
*/

package com.github.housepower.jdbc;
package com.github.housepower.jdbc.type;

import com.github.housepower.jdbc.AbstractITest;
import com.github.housepower.misc.BytesHelper;
import org.junit.jupiter.api.Test;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
* limitations under the License.
*/

package com.github.housepower.jdbc;
package com.github.housepower.jdbc.type;

import com.github.housepower.jdbc.AbstractITest;
import com.github.housepower.jdbc.ClickHouseArray;
import com.github.housepower.misc.BytesHelper;
import com.google.common.base.Strings;
import org.junit.jupiter.api.Test;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Licensed 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 com.github.housepower.jdbc.type;

import com.github.housepower.jdbc.AbstractITest;
import com.github.housepower.misc.BytesHelper;
import org.junit.jupiter.api.Test;

import java.sql.PreparedStatement;
import java.sql.ResultSet;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class IPv4TypeITest extends AbstractITest implements BytesHelper {

@Test
public void testIPv4Type() throws Exception {
withStatement(statement -> {
statement.execute("DROP TABLE IF EXISTS ipv4_test");
statement.execute("CREATE TABLE IF NOT EXISTS ipv4_test (value IPv4, nullableValue Nullable(IPv4)) Engine=Memory()");

Integer rowCnt = 300;
Long testIPv4Value1 = ipToLong("192.168.1.1");
Long testIPv4Value2 = ipToLong("127.0.0.1");

try (PreparedStatement pstmt = statement.getConnection().prepareStatement(
"INSERT INTO ipv4_test (value, nullableValue) values(?, ?);")) {
for (int i = 0; i < rowCnt; i++) {
pstmt.setLong(1, testIPv4Value1);
pstmt.setLong(2, testIPv4Value2);
pstmt.addBatch();
}
pstmt.executeBatch();
}

ResultSet rs = statement.executeQuery("SELECT * FROM ipv4_test;");
int size = 0;
while (rs.next()) {
size++;
Long value = rs.getLong(1);
assertEquals(value, testIPv4Value1);
Long nullableValue = rs.getLong(2);
assertEquals(nullableValue, testIPv4Value2);
}

assertEquals(size, (int) rowCnt);

statement.execute("DROP TABLE IF EXISTS ipv4_test");
});
}

public long ipToLong(String ipAddress) {
String[] ipAddressInArray = ipAddress.split("\\.");

long result = 0;
for (int i = 0; i < ipAddressInArray.length; i++) {
int power = 3 - i;
int ip = Integer.parseInt(ipAddressInArray[i]);
result += ip * Math.pow(256, power);
}

return result;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Licensed 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 com.github.housepower.jdbc.type;

import com.github.housepower.jdbc.AbstractITest;
import com.github.housepower.jdbc.ClickHouseResultSet;
import com.github.housepower.misc.BytesHelper;
import org.junit.jupiter.api.Test;

import java.math.BigInteger;
import java.sql.PreparedStatement;
import java.sql.Types;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class IPv6TypeITest extends AbstractITest implements BytesHelper {

@Test
public void testIPv6Type() throws Exception {
withStatement(statement -> {
statement.execute("DROP TABLE IF EXISTS ipv6_test");
statement.execute("CREATE TABLE IF NOT EXISTS ipv6_test (value IPv6, nullableValue Nullable(IPv6)) Engine=Memory()");

Integer rowCnt = 300;

BigInteger testIPv6Value1 = new BigInteger("20010db885a3000000008a2e03707334", 16);
BigInteger testIPv6Value2 = new BigInteger("1", 16);

try (PreparedStatement pstmt = statement.getConnection().prepareStatement(
"INSERT INTO ipv6_test (value, nullableValue) values(?, ?);")) {
for (int i = 0; i < rowCnt; i++) {
pstmt.setObject(1, testIPv6Value1, Types.BIGINT);
pstmt.setObject(2, testIPv6Value2, Types.BIGINT);
pstmt.addBatch();
}
pstmt.executeBatch();
}

ClickHouseResultSet rs = (ClickHouseResultSet) statement.executeQuery("SELECT * FROM ipv6_test;");
int size = 0;
while (rs.next()) {
size++;
BigInteger value = rs.getBigInteger(1);
assertEquals(value, testIPv6Value1);
BigInteger nullableValue = rs.getBigInteger(2);
assertEquals(nullableValue, testIPv6Value2);
}

assertEquals(size, (int) rowCnt);

statement.execute("DROP TABLE IF EXISTS ipv6_test");
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
* limitations under the License.
*/

package com.github.housepower.jdbc;
package com.github.housepower.jdbc.type;

import com.github.housepower.jdbc.AbstractITest;
import com.github.housepower.misc.BytesHelper;
import org.junit.jupiter.api.Test;

Expand Down

0 comments on commit 3d25086

Please sign in to comment.