Skip to content

Commit

Permalink
Fix null DECIMAL_DIGITS and CHAR_OCTET_LENGTH
Browse files Browse the repository at this point in the history
  • Loading branch information
zhicwu committed Jan 18, 2022
1 parent d42ede2 commit 2631c0d
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 14 deletions.
Expand Up @@ -45,6 +45,7 @@ public final class ClickHouseColumn implements Serializable {
private static ClickHouseColumn update(ClickHouseColumn column) {
column.enumConstants = ClickHouseEnum.EMPTY;
int size = column.parameters.size();
column.precision = column.dataType.getMaxPrecision();
switch (column.dataType) {
case Array:
column.arrayLevel = 1;
Expand Down
Expand Up @@ -44,15 +44,15 @@ public enum ClickHouseDataType {
UInt32(Long.class, false, true, false, 4, 10, 0, 0, 0, "INT UNSIGNED", "INTEGER UNSIGNED", "MEDIUMINT UNSIGNED"),
UInt64(Long.class, false, true, false, 8, 20, 0, 0, 0, "BIGINT UNSIGNED"),
UInt128(BigInteger.class, false, true, false, 16, 39, 0, 0, 0),
UInt256(BigInteger.class, false, true, false, 32, 78, 0, 0, 0), Int8(Byte.class, false, true, true, 1, 3, 0, 0, 0,
"BYTE", "INT1", "INT1 SIGNED", "TINYINT", "TINYINT SIGNED"),
UInt256(BigInteger.class, false, true, false, 32, 78, 0, 0, 0),
Int8(Byte.class, false, true, true, 1, 3, 0, 0, 0, "BYTE", "INT1", "INT1 SIGNED", "TINYINT", "TINYINT SIGNED"),
Int16(Short.class, false, true, true, 2, 5, 0, 0, 0, "SMALLINT", "SMALLINT SIGNED"),
Int32(Integer.class, false, true, true, 4, 10, 0, 0, 0, "INT", "INTEGER", "MEDIUMINT", "INT SIGNED",
"INTEGER SIGNED", "MEDIUMINT SIGNED"),
Int64(Long.class, false, true, true, 8, 19, 0, 0, 0, "BIGINT", "BIGINT SIGNED"),
Int128(BigInteger.class, false, true, true, 16, 39, 0, 0, 0),
Int256(BigInteger.class, false, true, true, 32, 77, 0, 0, 0),
Bool(Boolean.class, false, false, true, 1, 3, 0, 0, 0, "BOOLEAN"),
Bool(Boolean.class, false, false, true, 1, 1, 0, 0, 0, "BOOLEAN"),
Date(LocalDate.class, false, false, false, 2, 10, 0, 0, 0),
Date32(LocalDate.class, false, false, false, 4, 10, 0, 0, 0),
DateTime(LocalDateTime.class, true, false, false, 0, 29, 0, 0, 9, "TIMESTAMP"),
Expand All @@ -63,12 +63,15 @@ public enum ClickHouseDataType {
Decimal64(BigDecimal.class, true, false, true, 8, 18, 18, 0, 18),
Decimal128(BigDecimal.class, true, false, true, 16, 38, 38, 0, 38),
Decimal256(BigDecimal.class, true, false, true, 32, 76, 20, 0, 76),
UUID(UUID.class, false, true, false, 16, 69, 0, 0, 0), Enum(String.class, true, true, false, 1, 0, 0, 0, 0),
Enum8(String.class, true, true, false, 1, 0, 0, 0, 0), Enum16(String.class, true, true, false, 2, 0, 0, 0, 0),
UUID(UUID.class, false, true, false, 16, 69, 0, 0, 0),
@Deprecated
Enum(String.class, true, true, false, 1, 0, 0, 0, 0),
Enum8(String.class, true, true, false, 1, 0, 0, 0, 0), // "ENUM"),
Enum16(String.class, true, true, false, 2, 0, 0, 0, 0),
Float32(Float.class, false, true, true, 4, 12, 0, 0, 38, "FLOAT", "REAL", "SINGLE"),
Float64(Double.class, false, true, true, 16, 22, 0, 0, 308, "DOUBLE", "DOUBLE PRECISION"),
IPv4(Inet4Address.class, false, true, false, 4, 0, 0, 0, 0, "INET4"),
IPv6(Inet6Address.class, false, true, false, 16, 0, 0, 0, 0, "INET6"),
IPv4(Inet4Address.class, false, true, false, 4, 10, 0, 0, 0, "INET4"),
IPv6(Inet6Address.class, false, true, false, 16, 39, 0, 0, 0, "INET6"),
FixedString(String.class, true, true, false, 0, 0, 0, 0, 0, "BINARY"),
String(String.class, false, true, false, 0, 0, 0, 0, 0, "BINARY LARGE OBJECT", "BINARY VARYING", "BLOB", "BYTEA",
"CHAR", "CHAR LARGE OBJECT", "CHAR VARYING", "CHARACTER", "CHARACTER LARGE OBJECT", "CHARACTER VARYING",
Expand All @@ -77,8 +80,10 @@ public enum ClickHouseDataType {
"NCHAR LARGE OBJECT", "NCHAR VARYING", "NVARCHAR", "TEXT", "TINYBLOB", "TINYTEXT", "VARCHAR", "VARCHAR2"),
AggregateFunction(String.class, true, true, false, 0, 0, 0, 0, 0), // implementation-defined intermediate state
SimpleAggregateFunction(String.class, true, true, false, 0, 0, 0, 0, 0),
Array(Object.class, true, true, false, 0, 0, 0, 0, 0), Map(Map.class, true, true, false, 0, 0, 0, 0, 0),
Nested(Object.class, true, true, false, 0, 0, 0, 0, 0), Tuple(List.class, true, true, false, 0, 0, 0, 0, 0),
Array(Object.class, true, true, false, 0, 0, 0, 0, 0),
Map(Map.class, true, true, false, 0, 0, 0, 0, 0),
Nested(Object.class, true, true, false, 0, 0, 0, 0, 0),
Tuple(List.class, true, true, false, 0, 0, 0, 0, 0),
Point(Object.class, false, true, true, 33, 0, 0, 0, 0), // same as Tuple(Float64, Float64)
Polygon(Object.class, false, true, true, 0, 0, 0, 0, 0), // same as Array(Ring)
MultiPolygon(Object.class, false, true, true, 0, 0, 0, 0, 0), // same as Array(Polygon)
Expand Down
Expand Up @@ -814,9 +814,9 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa
String sql = ClickHouseParameterizedQuery
.apply("select null as TABLE_CAT, database as TABLE_SCHEM, table as TABLE_NAME, "
+ "name as COLUMN_NAME, toInt32(:defaultType) as DATA_TYPE, type as TYPE_NAME, toInt32(0) as COLUMN_SIZE, "
+ "0 as BUFFER_LENGTH, toInt32(null) as DECIMAL_DIGITS, 10 as NUM_PREC_RADIX, "
+ "0 as BUFFER_LENGTH, cast(null as Nullable(Int32)) as DECIMAL_DIGITS, 10 as NUM_PREC_RADIX, "
+ "toInt32(position(type, 'Nullable(') >= 1 ? :defaultNullable : :defaultNonNull) as NULLABLE, :comment as REMARKS, default_expression as COLUMN_DEF, "
+ "0 as SQL_DATA_TYPE, 0 as SQL_DATETIME_SUB, toInt32(null) as CHAR_OCTET_LENGTH, position as ORDINAL_POSITION, "
+ "0 as SQL_DATA_TYPE, 0 as SQL_DATETIME_SUB, cast(null as Nullable(Int32)) as CHAR_OCTET_LENGTH, position as ORDINAL_POSITION, "
+ "position(type, 'Nullable(') >= 1 ? 'YES' : 'NO' as IS_NULLABLE, null as SCOPE_CATALOG, null as SCOPE_SCHEMA, null as SCOPE_TABLE, "
+ "null as SOURCE_DATA_TYPE, 'NO' as IS_AUTOINCREMENT, 'NO' as IS_GENERATEDCOLUMN from system.columns\n"
+ "where database like :database and table like :table and name like :column", params);
Expand All @@ -825,7 +825,8 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa
try {
ClickHouseColumn column = ClickHouseColumn.of("", typeName);
r.getValue("DATA_TYPE").update(JdbcTypeMapping.toJdbcType(typeMaps, column));
r.getValue("COLUMN_SIZE").update(column.getDataType().getByteLength());
r.getValue("COLUMN_SIZE").update(
column.getPrecision() > 0 ? column.getPrecision() : column.getDataType().getByteLength());
if (column.isNullable()) {
r.getValue("NULLABLE").update(DatabaseMetaData.typeNullable);
r.getValue("IS_NULLABLE").update("YES");
Expand All @@ -838,7 +839,8 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa
r.getValue("CHAR_OCTET_LENGTH").update(column.getPrecision());
}

if (column.getScale() > 0) {
if (column.getScale() > 0 || column.getDataType() == ClickHouseDataType.Float32
|| column.getDataType() == ClickHouseDataType.Float64) {
r.getValue("DECIMAL_DIGITS").update(column.getScale());
} else {
r.getValue("DECIMAL_DIGITS").resetToNullOrEmpty();
Expand Down
Expand Up @@ -6,10 +6,28 @@
import java.util.Locale;
import java.util.Properties;

import com.clickhouse.client.ClickHouseColumn;

import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class ClickHouseDatabaseMetaDataTest extends JdbcIntegrationTest {
@DataProvider(name = "selectedColumns")
private Object[][] getSelectedColumns() {
return new Object[][] {
// COLUMN_SIZE, DECIMAL_DIGITS, CHAR_OCTET_LENGTH
new Object[] { "Bool", 1, null, null },
new Object[] { "Int8", 3, null, null },
new Object[] { "UInt8", 3, null, null },
new Object[] { "FixedString(3)", 3, null, 3 },
new Object[] { "String", 0, null, null },
new Object[] { "Decimal64(10)", 18, 10, null },
new Object[] { "Decimal(10,2)", 10, 2, null },
new Object[] { "Float32", 12, 0, null },
new Object[] { "Float64", 22, 0, null } };
}

@Test(groups = "integration")
public void testGetTypeInfo() throws SQLException {
Properties props = new Properties();
Expand All @@ -21,6 +39,26 @@ public void testGetTypeInfo() throws SQLException {
}
}

@Test(dataProvider = "selectedColumns", groups = "integration")
public void testGetColumns(String columnType, Integer columnSize, Integer decimalDigits, Integer octectLength)
throws SQLException {
ClickHouseColumn c = ClickHouseColumn.of("x", columnType);
String tableName = "test_get_column_" + c.getDataType().name().toLowerCase();
try (ClickHouseConnection conn = newConnection(new Properties());
Statement s = conn.createStatement()) {
s.execute("drop table if exists " + tableName + "; "
+ "create table " + tableName + "(x " + columnType + ") engine=Memory");
try (ResultSet rs = conn.getMetaData().getColumns(conn.getCatalog(), conn.getSchema(), tableName, "%")) {
Assert.assertTrue(rs.next(), "Should have one record");
Assert.assertEquals(rs.getString("cOLUMN_NAME"), "x");
Assert.assertEquals(rs.getObject("COLUMN_SIZE"), columnSize);
Assert.assertEquals(rs.getObject("DECIMAL_DIGITS"), decimalDigits);
Assert.assertEquals(rs.getObject("CHAR_OCTET_LENGTH"), octectLength);
Assert.assertFalse(rs.next(), "Should have only one record");
}
}
}

@Test(groups = "integration")
public void testTableComment() throws SQLException {
String tableName = "test_table_comment";
Expand All @@ -35,7 +73,7 @@ public void testTableComment() throws SQLException {
s.execute(String.format(Locale.ROOT,
"drop table if exists %1$s; create table %1$s(s String) engine=Memory comment '%2$s'",
tableName, tableComment));
try (ResultSet rs = conn.getMetaData().getTables(null, "%", tableName, null)) {
try (ResultSet rs = conn.getMetaData().getTables(conn.getCatalog(), conn.getSchema(), tableName, null)) {
Assert.assertTrue(rs.next());
Assert.assertEquals(rs.getString("remarks"), tableComment);
Assert.assertFalse(rs.next());
Expand Down

0 comments on commit 2631c0d

Please sign in to comment.