Skip to content

Commit

Permalink
[#442]: Support LowCardinality series datatype
Browse files Browse the repository at this point in the history
  • Loading branch information
demetribu committed Sep 22, 2023
1 parent fe79d3e commit de3d9b4
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,7 @@
import com.github.housepower.data.type.DataTypeUInt64;
import com.github.housepower.data.type.DataTypeUInt8;
import com.github.housepower.data.type.DataTypeUUID;
import com.github.housepower.data.type.complex.DataTypeArray;
import com.github.housepower.data.type.complex.DataTypeCreator;
import com.github.housepower.data.type.complex.DataTypeDateTime;
import com.github.housepower.data.type.complex.DataTypeDateTime64;
import com.github.housepower.data.type.complex.DataTypeDecimal;
import com.github.housepower.data.type.complex.DataTypeEnum16;
import com.github.housepower.data.type.complex.DataTypeEnum8;
import com.github.housepower.data.type.complex.DataTypeFixedString;
import com.github.housepower.data.type.complex.DataTypeMap;
import com.github.housepower.data.type.complex.DataTypeNothing;
import com.github.housepower.data.type.complex.DataTypeNullable;
import com.github.housepower.data.type.complex.DataTypeString;
import com.github.housepower.data.type.complex.DataTypeTuple;
import com.github.housepower.data.type.complex.*;
import com.github.housepower.misc.LRUCache;
import com.github.housepower.misc.SQLLexer;
import com.github.housepower.misc.Validate;
Expand Down Expand Up @@ -89,6 +77,8 @@ public class DataTypeFactory {
return DataTypeDateTime64.creator.createDataType(lexer, serverContext);
} else if (dataTypeName.equalsIgnoreCase("Nullable")) {
return DataTypeNullable.creator.createDataType(lexer, serverContext);
} else if (dataTypeName.equalsIgnoreCase("LowCardinality")) {
return DataTypeLowCardinality.creator.createDataType(lexer, serverContext);
} else if (dataTypeName.equalsIgnoreCase("FixedString") || dataTypeName.equals("Binary")) {
return DataTypeFixedString.creator.createDataType(lexer, serverContext);
} else if (dataTypeName.equalsIgnoreCase("Decimal")) {
Expand All @@ -98,7 +88,7 @@ public class DataTypeFactory {
} else if (dataTypeName.equalsIgnoreCase("Nothing")) {
return DataTypeNothing.CREATOR.createDataType(lexer, serverContext);
} else if (dataTypeName.equalsIgnoreCase("Map")) {
return DataTypeMap.creator.createDataType(lexer, serverContext);
return DataTypeMap.creator.createDataType(lexer, serverContext);
} else {
IDataType<?, ?> dataType = dataTypes.get(dataTypeName.toLowerCase(Locale.ROOT));
Validate.isTrue(dataType != null, "Unknown data type: " + dataTypeName);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package com.github.housepower.data.type.complex;

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

import java.io.IOException;
import java.sql.SQLException;

public class DataTypeLowCardinality implements IDataType {

public static DataTypeCreator creator = (lexer, serverContext) -> {
Validate.isTrue(lexer.character() == '(');
IDataType nestedType = DataTypeFactory.get(lexer, serverContext);
Validate.isTrue(lexer.character() == ')');
return new DataTypeLowCardinality(
"LowCardinality(" + nestedType.name() + ")", nestedType);
};

private final String name;
private final IDataType nestedDataType;

public DataTypeLowCardinality(String name, IDataType nestedDataType) {
this.name = name;
this.nestedDataType = nestedDataType;
}

@Override
public String name() {
return this.name;
}

@Override
public int sqlTypeId() {
return this.nestedDataType.sqlTypeId();
}

@Override
public Object defaultValue() {
return this.nestedDataType.defaultValue();
}

@Override
public Class javaType() {
return this.nestedDataType.javaType();
}

@Override
public Class jdbcJavaType() {
return this.nestedDataType.jdbcJavaType();
}

@Override
public boolean nullable() {
return this.nestedDataType.nullable();
}

@Override
public int getPrecision() {
return this.nestedDataType.getPrecision();
}

@Override
public int getScale() {
return this.nestedDataType.getScale();
}

@Override
public Object deserializeText(SQLLexer lexer) throws SQLException {
return this.nestedDataType.deserializeText(lexer);
}

@Override
public void serializeBinary(Object data, BinarySerializer serializer) throws SQLException, IOException {
this.nestedDataType.serializeBinary(data, serializer);
}

@Override
public void serializeBinaryBulk(Object[] data, BinarySerializer serializer) throws SQLException, IOException {
this.nestedDataType.serializeBinaryBulk(data, serializer);
}

@Override
public Object deserializeBinary(BinaryDeserializer deserializer) throws SQLException, IOException {
return this.nestedDataType.deserializeBinary(deserializer);
}

@Override
public Object[] deserializeBinaryBulk(int rows, BinaryDeserializer deserializer) throws SQLException, IOException {
Object[] data = this.nestedDataType.deserializeBinaryBulk(rows, deserializer);
return data;
}

@Override
public boolean isSigned() {
return this.nestedDataType.isSigned();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.github.housepower.jdbc;

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

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

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

//Refer to [[https://github.com/housepower/ClickHouse-Native-JDBC/issues/442]] for more details.
public class LowCardinalityTypeTest extends AbstractITest implements BytesHelper {
@Test
public void testLowCardinalityType() throws Exception {
withStatement(statement -> {
statement.execute("DROP TABLE IF EXISTS low_cardinality_test");
statement.execute("CREATE TABLE IF NOT EXISTS low_cardinality_test " +
"(value LowCardinality(String), nullable_value LowCardinality(Nullable(String))) Engine=Memory()");

String testValue = "value";
String sql = "INSERT INTO low_cardinality_test (value, nullable_value) values(?, ?);";
try (PreparedStatement pstmt = statement.getConnection().prepareStatement(sql)) {
for (int i = 0; i < 300; i++) {
pstmt.setString(1, testValue);
pstmt.setString(2, null);
pstmt.addBatch();
}
pstmt.executeBatch();
}

DatabaseMetaData metaData = statement.getConnection().getMetaData();
ResultSet columns = metaData.getColumns(null, "default", "low_cardinality_test", "%value%");
while (columns.next()) {
String columnName = columns.getString("COLUMN_NAME");
String columnType = columns.getString("TYPE_NAME");
boolean nullable = columns.getInt("NULLABLE") == DatabaseMetaData.columnNullable;

if (columnName.equals("value")) {
assertEquals(columnType, "LowCardinality(String)");
assertFalse(nullable);
} else {
assertEquals(columnType, "LowCardinality(Nullable(String))");
assertTrue(nullable);
}
}

ResultSet rs = statement.executeQuery("SELECT * FROM low_cardinality_test;");
int size = 0;
while (rs.next()) {
String value = rs.getString(1);
String nullableValue = rs.getString(2);
assertEquals(testValue, value);
assertNull(nullableValue);
size++;
}
assertEquals(300, size);
statement.execute("DROP TABLE IF EXISTS decimal_test");
});
}
}

0 comments on commit de3d9b4

Please sign in to comment.