diff --git a/jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/JdbcUtils.java b/jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/JdbcUtils.java index 1b0f9c12b..abf7f2b69 100644 --- a/jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/JdbcUtils.java +++ b/jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/JdbcUtils.java @@ -6,12 +6,15 @@ import com.clickhouse.jdbc.types.Array; import com.google.common.collect.ImmutableMap; +import java.awt.*; +import java.math.BigInteger; import java.net.Inet4Address; import java.net.Inet6Address; import java.sql.Date; import java.sql.JDBCType; import java.sql.SQLException; import java.sql.SQLType; +import java.sql.Types; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -42,6 +45,14 @@ private static Map generateTypeMap() { map.put(ClickHouseDataType.Int16, JDBCType.SMALLINT); map.put(ClickHouseDataType.Int32, JDBCType.INTEGER); map.put(ClickHouseDataType.Int64, JDBCType.BIGINT); + map.put(ClickHouseDataType.Int128, JDBCType.OTHER); + map.put(ClickHouseDataType.Int256, JDBCType.OTHER); + map.put(ClickHouseDataType.UInt8, JDBCType.SMALLINT); + map.put(ClickHouseDataType.UInt16, JDBCType.INTEGER); + map.put(ClickHouseDataType.UInt32, JDBCType.BIGINT); + map.put(ClickHouseDataType.UInt64, JDBCType.OTHER); + map.put(ClickHouseDataType.UInt128, JDBCType.OTHER); + map.put(ClickHouseDataType.UInt256, JDBCType.OTHER); map.put(ClickHouseDataType.Float32, JDBCType.FLOAT); map.put(ClickHouseDataType.Float64, JDBCType.DOUBLE); map.put(ClickHouseDataType.Bool, JDBCType.BOOLEAN); @@ -81,8 +92,8 @@ private static Map> generateClassMap() { map.put(JDBCType.DECIMAL, java.math.BigDecimal.class); map.put(JDBCType.BIT, Boolean.class); map.put(JDBCType.BOOLEAN, Boolean.class); - map.put(JDBCType.TINYINT, Integer.class); - map.put(JDBCType.SMALLINT, Integer.class); + map.put(JDBCType.TINYINT, Byte.class); + map.put(JDBCType.SMALLINT, Short.class); map.put(JDBCType.INTEGER, Integer.class); map.put(JDBCType.BIGINT, Long.class); map.put(JDBCType.REAL, Float.class); @@ -115,9 +126,44 @@ private static Map> generateClassMap() { private static Map> getDataTypeClassMap() { Map> map = new HashMap<>(); for (Map.Entry e : CLICKHOUSE_TO_SQL_TYPE_MAP.entrySet()) { - map.put(e.getKey(), SQL_TYPE_TO_CLASS_MAP.get(e.getValue())); + if (e.getValue().equals(JDBCType.OTHER)) { + switch (e.getKey()) { + case UInt64: + map.put(e.getKey(), BigInteger.class); + break; + case UInt128: + map.put(e.getKey(), BigInteger.class); + break; + case UInt256: + map.put(e.getKey(), BigInteger.class); + break; + case Int128: + map.put(e.getKey(), BigInteger.class); + break; + case Int256: + map.put(e.getKey(), BigInteger.class); + break; + case Point: + map.put(e.getKey(), double[].class); + break; + case LineString: + case Ring: + map.put(e.getKey(), double[][].class); + break; + case Polygon: + case MultiLineString: + map.put(e.getKey(), double[][][].class); + break; + case MultiPolygon: + map.put(e.getKey(), double[][][][].class); + break; + default: + map.put(e.getKey(), Object.class); + } + } else { + map.put(e.getKey(), SQL_TYPE_TO_CLASS_MAP.get(e.getValue())); + } } - return map; } diff --git a/jdbc-v2/src/main/java/com/clickhouse/jdbc/metadata/DatabaseMetaDataImpl.java b/jdbc-v2/src/main/java/com/clickhouse/jdbc/metadata/DatabaseMetaDataImpl.java index b6251107f..f433f749a 100644 --- a/jdbc-v2/src/main/java/com/clickhouse/jdbc/metadata/DatabaseMetaDataImpl.java +++ b/jdbc-v2/src/main/java/com/clickhouse/jdbc/metadata/DatabaseMetaDataImpl.java @@ -688,11 +688,14 @@ public boolean dataDefinitionIgnoredInTransactions() throws SQLException { @Override public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException { String sql = "SELECT " + - "'' AS FUNCTION_CAT, " + - "'' AS FUNCTION_SCHEM, " + - "'' AS FUNCTION_NAME, " + + "'' AS PROCEDURE_CAT, " + + "'' AS PROCEDURE_SCHEM, " + + "'' AS PROCEDURE_NAME, " + + "0::Int16 AS RESERVED1, " + + "0::Int16 AS RESERVED2, " + + "0::Int16 AS RESERVED3, " + "'' AS REMARKS, " + - "0 AS FUNCTION_TYPE, " + + "0::Int16 AS PROCEDURE_TYPE, " + "'' AS SPECIFIC_NAME " + "LIMIT 0"; try { @@ -709,20 +712,20 @@ public ResultSet getProcedureColumns(String catalog, String schemaPattern, Strin "'' AS PROCEDURE_SCHEM, " + "'' AS PROCEDURE_NAME, " + "'' AS COLUMN_NAME, " + - "0 AS COLUMN_TYPE, " + - "0 AS DATA_TYPE, " + + "0::Int16 AS COLUMN_TYPE, " + + "0::Int32 AS DATA_TYPE, " + "'' AS TYPE_NAME, " + - "0 AS PRECISION, " + - "0 AS LENGTH, " + - "0 AS SCALE, " + - "0 AS RADIX, " + - "0 AS NULLABLE, " + + "0::Int32 AS PRECISION, " + + "0::Int32 AS LENGTH, " + + "0::Int16 AS SCALE, " + + "0::Int16 AS RADIX, " + + "0::Int16 AS NULLABLE, " + "'' AS REMARKS, " + "'' AS COLUMN_DEF, " + - "0 AS SQL_DATA_TYPE, " + - "0 AS SQL_DATETIME_SUB, " + - "0 AS CHAR_OCTET_LENGTH, " + - "0 AS ORDINAL_POSITION, " + + "0::Int32 AS SQL_DATA_TYPE, " + + "0::Int32 AS SQL_DATETIME_SUB, " + + "0::Int32 AS CHAR_OCTET_LENGTH, " + + "0::Int32 AS ORDINAL_POSITION, " + "'' AS IS_NULLABLE, " + "'' AS SPECIFIC_NAME " + "LIMIT 0"; @@ -762,11 +765,11 @@ public ResultSet getTables(String catalog, String schemaPattern, String tableNam "WHEN empty(t.data_paths) THEN 'REMOTE TABLE' " + "ELSE 'TABLE' END AS TABLE_TYPE, " + "t.comment AS REMARKS, " + - "null AS TYPE_CAT, " + // no types catalog + "null::Nullable(String) AS TYPE_CAT, " + // no types catalog "d.engine AS TYPE_SCHEM, " + // no types schema - "null AS TYPE_NAME, " + // vendor type name ? - "null AS SELF_REFERENCING_COL_NAME, " + - "null AS REF_GENERATION" + + "null::Nullable(String) AS TYPE_NAME, " + // vendor type name ? + "null::Nullable(String) AS SELF_REFERENCING_COL_NAME, " + + "null::Nullable(String) AS REF_GENERATION" + " FROM system.tables t" + " JOIN system.databases d ON system.tables.database = system.databases.name" + " WHERE t.database LIKE '" + (schemaPattern == null ? "%" : schemaPattern) + "'" + @@ -840,22 +843,22 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa "name AS COLUMN_NAME, " + "system.columns.type AS DATA_TYPE, " + "type AS TYPE_NAME, " + - generateSqlTypeSizes("system.columns.type") + " AS COLUMN_SIZE, " + + "toInt32(" + generateSqlTypeSizes("system.columns.type") + ") AS COLUMN_SIZE, " + "toInt32(0) AS BUFFER_LENGTH, " + - "IF (numeric_scale == 0, NULL, numeric_scale) as DECIMAL_DIGITS, " + + "toInt32(IF (numeric_scale == 0, NULL, numeric_scale)) as DECIMAL_DIGITS, " + "toInt32(numeric_precision_radix) AS NUM_PREC_RADIX, " + "toInt32(position(type, 'Nullable(') >= 1 ?" + java.sql.DatabaseMetaData.typeNullable + " : " + java.sql.DatabaseMetaData.typeNoNulls + ") as NULLABLE, " + "system.columns.comment AS REMARKS, " + "system.columns.default_expression AS COLUMN_DEF, " + "toInt32(0) AS SQL_DATA_TYPE, " + "toInt32(0) AS SQL_DATETIME_SUB, " + - "character_octet_length AS CHAR_OCTET_LENGTH, " + + "character_octet_length::Nullable(Int32) AS CHAR_OCTET_LENGTH, " + "toInt32(system.columns.position) AS ORDINAL_POSITION, " + "position(upper(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, " + + "NULL::Nullable(String) AS SCOPE_CATALOG, " + + "NULL::Nullable(String) AS SCOPE_SCHEMA, " + + "NULL::Nullable(String) AS SCOPE_TABLE, " + + "NULL::Nullable(Int16) AS SOURCE_DATA_TYPE, " + "'NO' as IS_AUTOINCREMENT, " + "'NO' as IS_GENERATEDCOLUMN " + " FROM system.columns" + @@ -902,7 +905,14 @@ public ResultSet getColumnPrivileges(String catalog, String schema, String table //Return an empty result set with the required columns log.warn("getColumnPrivileges is not supported and may return invalid results"); try { - return connection.createStatement().executeQuery("SELECT NULL AS TABLE_CAT, NULL AS TABLE_SCHEM, NULL AS TABLE_NAME, NULL AS COLUMN_NAME, NULL AS GRANTOR, NULL AS GRANTEE, NULL AS PRIVILEGE, NULL AS IS_GRANTABLE"); + return connection.createStatement().executeQuery("SELECT NULL::Nullable(String) AS TABLE_CAT, " + + "NULL::Nullable(String) AS TABLE_SCHEM, " + + "NULL::Nullable(String) AS TABLE_NAME, " + + "NULL::Nullable(String) AS COLUMN_NAME, " + + "NULL::Nullable(String) AS GRANTOR, " + + "NULL::Nullable(String) AS GRANTEE, " + + "NULL::Nullable(String) AS PRIVILEGE, " + + "NULL::Nullable(String) AS IS_GRANTABLE"); } catch (Exception e) { throw ExceptionUtils.toSqlState(e); } @@ -913,7 +923,13 @@ public ResultSet getTablePrivileges(String catalog, String schemaPattern, String //Return an empty result set with the required columns log.warn("getTablePrivileges is not supported and may return invalid results"); try { - return connection.createStatement().executeQuery("SELECT NULL AS TABLE_CAT, NULL AS TABLE_SCHEM, NULL AS TABLE_NAME, NULL AS GRANTOR, NULL AS GRANTEE, NULL AS PRIVILEGE, NULL AS IS_GRANTABLE"); + return connection.createStatement().executeQuery("SELECT NULL::Nullable(String) AS TABLE_CAT, " + + "NULL::Nullable(String) AS TABLE_SCHEM, " + + "NULL::Nullable(String) AS TABLE_NAME, " + + "NULL::Nullable(String) AS GRANTOR, " + + "NULL::Nullable(String) AS GRANTEE, " + + "NULL::Nullable(String) AS PRIVILEGE, " + + "NULL::Nullable(String) AS IS_GRANTABLE"); } catch (Exception e) { throw ExceptionUtils.toSqlState(e); } @@ -924,7 +940,14 @@ public ResultSet getBestRowIdentifier(String catalog, String schema, String tabl //Return an empty result set with the required columns log.warn("getBestRowIdentifier is not supported and may return invalid results"); try { - return connection.createStatement().executeQuery("SELECT NULL AS SCOPE, NULL AS COLUMN_NAME, NULL AS DATA_TYPE, NULL AS TYPE_NAME, NULL AS COLUMN_SIZE, NULL AS BUFFER_LENGTH, NULL AS DECIMAL_DIGITS, NULL AS PSEUDO_COLUMN"); + return connection.createStatement().executeQuery("SELECT NULL::Nullable(Int16) AS SCOPE, " + + "NULL::Nullable(String) AS COLUMN_NAME, " + + "NULL::Nullable(Int32) AS DATA_TYPE, " + + "NULL::Nullable(String) AS TYPE_NAME, " + + "NULL::Nullable(Int32) AS COLUMN_SIZE, " + + "NULL::Nullable(Int32) AS BUFFER_LENGTH, " + + "NULL::Nullable(Int16) AS DECIMAL_DIGITS, " + + "NULL::Nullable(Int16) AS PSEUDO_COLUMN"); } catch (Exception e) { throw ExceptionUtils.toSqlState(e); } @@ -935,7 +958,14 @@ public ResultSet getVersionColumns(String catalog, String schema, String table) //Return an empty result set with the required columns log.warn("getVersionColumns is not supported and may return invalid results"); try { - return connection.createStatement().executeQuery("SELECT NULL AS SCOPE, NULL AS COLUMN_NAME, NULL AS DATA_TYPE, NULL AS TYPE_NAME, NULL AS COLUMN_SIZE, NULL AS BUFFER_LENGTH, NULL AS DECIMAL_DIGITS, NULL AS PSEUDO_COLUMN"); + return connection.createStatement().executeQuery("SELECT NULL::Nullable(Int16) AS SCOPE, " + + "NULL::Nullable(String) AS COLUMN_NAME, " + + "NULL::Nullable(Int32) AS DATA_TYPE, " + + "NULL::Nullable(String) AS TYPE_NAME, " + + "NULL::Nullable(Int32) AS COLUMN_SIZE, " + + "NULL::Nullable(Int32) AS BUFFER_LENGTH, " + + "NULL::Nullable(Int16) AS DECIMAL_DIGITS, " + + "NULL::Nullable(Int16) AS PSEUDO_COLUMN"); } catch (Exception e) { throw ExceptionUtils.toSqlState(e); } @@ -944,11 +974,11 @@ public ResultSet getVersionColumns(String catalog, String schema, String table) @Override public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { try { - String sql = "SELECT NULL AS TABLE_CAT, " + + String sql = "SELECT NULL::Nullable(String) AS TABLE_CAT, " + "system.tables.database AS TABLE_SCHEM, " + "system.tables.name AS TABLE_NAME, " + "trim(c.1) AS COLUMN_NAME, " + - "c.2 AS KEY_SEQ, " + + "c.2::Int16 AS KEY_SEQ, " + "'PRIMARY' AS PK_NAME " + "FROM system.tables " + "ARRAY JOIN arrayZip(splitByChar(',', primary_key), arrayEnumerate(splitByChar(',', primary_key))) as c " + @@ -968,20 +998,20 @@ public ResultSet getImportedKeys(String catalog, String schema, String table) th //Return an empty result set with the required columns log.warn("getImportedKeys is not supported and may return invalid results"); try { - String sql = "SELECT NULL AS PKTABLE_CAT, " + - "NULL AS PKTABLE_SCHEM, " + - "NULL AS PKTABLE_NAME, " + - "NULL AS PKCOLUMN_NAME, " + - "NULL AS FKTABLE_CAT, " + - "NULL AS FKTABLE_SCHEM, " + - "NULL AS FKTABLE_NAME, " + - "NULL AS FKCOLUMN_NAME, " + - "NULL AS KEY_SEQ, " + - "NULL AS UPDATE_RULE, " + - "NULL AS DELETE_RULE, " + - "NULL AS FK_NAME, " + - "NULL AS PK_NAME, " + - "NULL AS DEFERRABILITY LIMIT 0"; + String sql = "SELECT NULL::Nullable(String) AS PKTABLE_CAT, " + + "NULL::Nullable(String) AS PKTABLE_SCHEM, " + + "NULL::Nullable(String) AS PKTABLE_NAME, " + + "NULL::Nullable(String) AS PKCOLUMN_NAME, " + + "NULL::Nullable(String) AS FKTABLE_CAT, " + + "NULL::Nullable(String) AS FKTABLE_SCHEM, " + + "NULL::Nullable(String) AS FKTABLE_NAME, " + + "NULL::Nullable(String) AS FKCOLUMN_NAME, " + + "NULL::Nullable(Int16) AS KEY_SEQ, " + + "NULL::Nullable(Int16) AS UPDATE_RULE, " + + "NULL::Nullable(Int16) AS DELETE_RULE, " + + "NULL::Nullable(String) AS FK_NAME, " + + "NULL::Nullable(String) AS PK_NAME, " + + "NULL::Nullable(Int16) AS DEFERRABILITY"; return connection.createStatement().executeQuery(sql); } catch (Exception e) { throw ExceptionUtils.toSqlState(e); @@ -993,7 +1023,20 @@ public ResultSet getExportedKeys(String catalog, String schema, String table) th //Return an empty result set with the required columns log.warn("getExportedKeys is not supported and may return invalid results"); try { - return connection.createStatement().executeQuery("SELECT NULL AS PKTABLE_CAT, NULL AS PKTABLE_SCHEM, NULL AS PKTABLE_NAME, NULL AS PKCOLUMN_NAME, NULL AS FKTABLE_CAT, NULL AS FKTABLE_SCHEM, NULL AS FKTABLE_NAME, NULL AS FKCOLUMN_NAME, NULL AS KEY_SEQ, NULL AS UPDATE_RULE, NULL AS DELETE_RULE, NULL AS FK_NAME, NULL AS PK_NAME, NULL AS DEFERRABILITY"); + return connection.createStatement().executeQuery("SELECT NULL::Nullable(String) AS PKTABLE_CAT, " + + "NULL::Nullable(String) AS PKTABLE_SCHEM, " + + "NULL::Nullable(String) AS PKTABLE_NAME, " + + "NULL::Nullable(String) AS PKCOLUMN_NAME, " + + "NULL::Nullable(String) AS FKTABLE_CAT, " + + "NULL::Nullable(String) AS FKTABLE_SCHEM, " + + "NULL::Nullable(String) AS FKTABLE_NAME, " + + "NULL::Nullable(String) AS FKCOLUMN_NAME, " + + "NULL::Nullable(Int16) AS KEY_SEQ, " + + "NULL::Nullable(Int16) AS UPDATE_RULE, " + + "NULL::Nullable(Int16) AS DELETE_RULE, " + + "NULL::Nullable(String) AS FK_NAME, " + + "NULL::Nullable(String) AS PK_NAME, " + + "NULL::Nullable(Int16) AS DEFERRABILITY"); } catch (Exception e) { throw ExceptionUtils.toSqlState(e); } @@ -1004,13 +1047,27 @@ public ResultSet getCrossReference(String parentCatalog, String parentSchema, St //Return an empty result set with the required columns log.warn("getCrossReference is not supported and may return invalid results"); try { - return connection.createStatement().executeQuery("SELECT NULL AS PKTABLE_CAT, NULL AS PKTABLE_SCHEM, NULL AS PKTABLE_NAME, NULL AS PKCOLUMN_NAME, NULL AS FKTABLE_CAT, NULL AS FKTABLE_SCHEM, NULL AS FKTABLE_NAME, NULL AS FKCOLUMN_NAME, NULL AS KEY_SEQ, NULL AS UPDATE_RULE, NULL AS DELETE_RULE, NULL AS FK_NAME, NULL AS PK_NAME"); + String columns = "NULL ::Nullable(String) AS PKTABLE_CAT, " + + "NULL::Nullable(String) AS PKTABLE_SCHEM, " + + "NULL::Nullable(String) AS PKTABLE_NAME, " + + "NULL::Nullable(String) AS PKCOLUMN_NAME, " + + "NULL::Nullable(String) AS FKTABLE_CAT, " + + "NULL::Nullable(String) AS FKTABLE_SCHEM, " + + "NULL::Nullable(String) AS FKTABLE_NAME, " + + "NULL::Nullable(String) AS FKCOLUMN_NAME, " + + "NULL::Nullable(Int16) AS KEY_SEQ, " + + "NULL::Nullable(Int16) AS UPDATE_RULE, " + + "NULL::Nullable(Int16) AS DELETE_RULE, " + + "NULL::Nullable(String) AS FK_NAME, " + + "NULL::Nullable(String) AS PK_NAME, " + + "NULL::Nullable(Int16) AS DEFERRABILITY"; + return connection.createStatement().executeQuery("SELECT " + columns); } catch (Exception e) { throw ExceptionUtils.toSqlState(e); } } - private static final ClickHouseColumn NULLABLE_COL = ClickHouseColumn.of("NULLABLE", ClickHouseDataType.Int32.name()); + private static final ClickHouseColumn NULLABLE_COL = ClickHouseColumn.of("NULLABLE", ClickHouseDataType.Int16.name()); @Override @SuppressWarnings({"squid:S2095"}) public ResultSet getTypeInfo() throws SQLException { @@ -1042,22 +1099,22 @@ private static String getDataTypeInfoSql() { StringBuilder sql = new StringBuilder("SELECT " + "name AS TYPE_NAME, " + "if(empty(alias_to), name, alias_to) AS DATA_TYPE, " + // passing type name or alias if exists to map then - "attrs.c2 AS PRECISION, " + - "NULL AS LITERAL_PREFIX, " + - "NULL AS LITERAL_SUFFIX, " + - "NULL AS CREATE_PARAMS, " + + "attrs.c2::Nullable(Int32) AS PRECISION, " + + "NULL::Nullable(String) AS LITERAL_PREFIX, " + + "NULL::Nullable(String) AS LITERAL_SUFFIX, " + + "NULL::Nullable(String) AS CREATE_PARAMS, " + "name AS NULLABLE, " + // passing type name to map for nullable "not(dt.case_insensitive)::Boolean AS CASE_SENSITIVE, " + - java.sql.DatabaseMetaData.typeSearchable + " AS SEARCHABLE, " + + java.sql.DatabaseMetaData.typeSearchable + "::Int16 AS SEARCHABLE, " + "not(attrs.c3)::Boolean AS UNSIGNED_ATTRIBUTE, " + "false AS FIXED_PREC_SCALE, " + "false AS AUTO_INCREMENT, " + "name AS LOCAL_TYPE_NAME, " + - "attrs.c4 AS MINIMUM_SCALE, " + - "attrs.c5 AS MAXIMUM_SCALE, " + - "0 AS SQL_DATA_TYPE, " + - "0 AS SQL_DATETIME_SUB, " + - "0 AS NUM_PREC_RADIX " + + "attrs.c4::Nullable(Int16) AS MINIMUM_SCALE, " + + "attrs.c5::Nullable(Int16) AS MAXIMUM_SCALE, " + + "0::Nullable(Int32) AS SQL_DATA_TYPE, " + + "0::Nullable(Int32) AS SQL_DATETIME_SUB, " + + "0::Nullable(Int32) AS NUM_PREC_RADIX " + "FROM system.data_type_families dt " + " LEFT JOIN (SELECT * FROM VALUES ( "); for (ClickHouseDataType type : ClickHouseDataType.values()) { @@ -1080,9 +1137,20 @@ private static String getDataTypeInfoSql() { @Override public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException { try { - String sql = "SELECT null AS TABLE_CAT, null AS TABLE_SCHEM, null AS TABLE_NAME, null AS NON_UNIQUE," + - " null AS INDEX_QUALIFIER, null AS INDEX_NAME, null AS TYPE, null AS ORDINAL_POSITION, null AS COLUMN_NAME, null AS ASC_OR_DESC," + - " null AS CARDINALITY, null AS PAGES, null AS FILTER_CONDITION LIMIT 0"; + String sql = "SELECT " + + "null::Nullable(String) AS TABLE_CAT, " + + "null::Nullable(String) AS TABLE_SCHEM, " + + "null::Nullable(String) AS TABLE_NAME, " + + "null::Nullable(Boolean) AS NON_UNIQUE, " + + "null::Nullable(String) AS INDEX_QUALIFIER, " + + "null::Nullable(String) AS INDEX_NAME, " + + "null::Nullable(Int16) AS TYPE, " + + "null::Nullable(Int16) AS ORDINAL_POSITION, " + + "null::Nullable(String) AS COLUMN_NAME, " + + "null::Nullable(String) AS ASC_OR_DESC, " + + "null::Nullable(Int64) AS CARDINALITY, " + + "null::Nullable(Int64) AS PAGES, " + + "null::Nullable(String) AS FILTER_CONDITION "; return connection.createStatement().executeQuery(sql); } catch (Exception e) { throw ExceptionUtils.toSqlState(e); @@ -1154,7 +1222,14 @@ public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePa //Return an empty result set with the required columns log.warn("getUDTs is not supported and may return invalid results"); try { - return connection.createStatement().executeQuery("SELECT NULL AS TYPE_CAT, NULL AS TYPE_SCHEM, NULL AS TYPE_NAME, NULL AS CLASS_NAME, NULL AS DATA_TYPE, NULL AS REMARKS, NULL AS BASE_TYPE"); + return connection.createStatement().executeQuery("SELECT " + + "NULL::Nullable(String) AS TYPE_CAT, " + + "NULL::Nullable(String) AS TYPE_SCHEM, " + + "NULL::Nullable(String) AS TYPE_NAME, " + + "NULL::Nullable(String) AS CLASS_NAME, " + + "NULL::Nullable(Int32) AS DATA_TYPE, " + + "NULL::Nullable(String) AS REMARKS, " + + "NULL::Nullable(Int16) AS BASE_TYPE"); } catch (Exception e) { throw ExceptionUtils.toSqlState(e); } @@ -1193,7 +1268,13 @@ public ResultSet getSuperTypes(String catalog, String schemaPattern, String type //Return an empty result set with the required columns log.warn("getSuperTypes is not supported and may return invalid results"); try { - return connection.createStatement().executeQuery("SELECT NULL AS TYPE_CAT, NULL AS TYPE_SCHEM, NULL AS TYPE_NAME, NULL AS SUPERTYPE_CAT, NULL AS SUPERTYPE_SCHEM, NULL AS SUPERTYPE_NAME"); + return connection.createStatement().executeQuery( + "SELECT NULL::Nullable(String) AS TYPE_CAT, " + + "NULL::Nullable(String) AS TYPE_SCHEM, " + + "NULL::Nullable(String) AS TYPE_NAME, " + + "NULL::Nullable(String) AS SUPERTYPE_CAT, " + + "NULL::Nullable(String) AS SUPERTYPE_SCHEM, " + + "NULL::Nullable(String) AS SUPERTYPE_NAME"); } catch (Exception e) { throw ExceptionUtils.toSqlState(e); } @@ -1204,7 +1285,12 @@ public ResultSet getSuperTables(String catalog, String schemaPattern, String tab //Return an empty result set with the required columns log.warn("getSuperTables is not supported and may return invalid results"); try { - return connection.createStatement().executeQuery("SELECT NULL AS TABLE_CAT, NULL AS TABLE_SCHEM, NULL AS TABLE_NAME, NULL AS SUPERTABLE_NAME"); + return connection.createStatement().executeQuery( + "SELECT " + + "NULL::Nullable(String) AS TABLE_CAT, " + + "NULL::Nullable(String) AS TABLE_SCHEM, " + + "NULL::Nullable(String) AS TABLE_NAME, " + + "NULL::Nullable(String) AS SUPERTABLE_NAME"); } catch (Exception e) { throw ExceptionUtils.toSqlState(e); } @@ -1215,7 +1301,29 @@ public ResultSet getAttributes(String catalog, String schemaPattern, String type //Return an empty result set with the required columns log.warn("getAttributes is not supported and may return invalid results"); try { - return connection.createStatement().executeQuery("SELECT NULL AS TYPE_CAT, NULL AS TYPE_SCHEM, NULL AS TYPE_NAME, NULL AS ATTR_NAME, NULL AS DATA_TYPE, NULL AS ATTR_TYPE_NAME, NULL AS ATTR_SIZE, NULL AS DECIMAL_DIGITS, NULL AS NUM_PREC_RADIX, NULL AS NULLABLE, NULL AS REMARKS, NULL AS ATTR_DEF, NULL AS SQL_DATA_TYPE, NULL AS SQL_DATETIME_SUB, NULL AS CHAR_OCTET_LENGTH, NULL AS ORDINAL_POSITION, NULL AS IS_NULLABLE, NULL AS SCOPE_CATALOG, NULL AS SCOPE_SCHEMA, NULL AS SCOPE_TABLE, NULL AS SOURCE_DATA_TYPE"); + return connection.createStatement().executeQuery( + "SELECT " + + "NULL::Nullable(String) AS TYPE_CAT, " + + "NULL::Nullable(String) AS TYPE_SCHEM, " + + "NULL::Nullable(String) AS TYPE_NAME, " + + "NULL::Nullable(String) AS ATTR_NAME, " + + "NULL::Nullable(Int32) AS DATA_TYPE, " + + "NULL::Nullable(String) AS ATTR_TYPE_NAME, " + + "NULL::Nullable(Int32) AS ATTR_SIZE, " + + "NULL::Nullable(Int32) AS DECIMAL_DIGITS, " + + "NULL::Nullable(Int32) AS NUM_PREC_RADIX, " + + "NULL::Nullable(Int32) AS NULLABLE, " + + "NULL::Nullable(String) AS REMARKS, " + + "NULL::Nullable(String) AS ATTR_DEF, " + + "NULL::Nullable(Int32) AS SQL_DATA_TYPE, " + + "NULL::Nullable(Int32) AS SQL_DATETIME_SUB, " + + "NULL::Nullable(Int32) AS CHAR_OCTET_LENGTH, " + + "NULL::Nullable(Int32) AS ORDINAL_POSITION, " + + "NULL::Nullable(String) AS IS_NULLABLE, " + + "NULL::Nullable(String) AS SCOPE_CATALOG, " + + "NULL::Nullable(String) AS SCOPE_SCHEMA, " + + "NULL::Nullable(String) AS SCOPE_TABLE, " + + "NULL::Nullable(Int16) AS SOURCE_DATA_TYPE"); } catch (Exception e) { throw ExceptionUtils.toSqlState(e); } @@ -1237,7 +1345,6 @@ public int getDatabaseMajorVersion() throws SQLException { try { return Integer.parseInt(version.split("\\.")[0]); } catch (NumberFormatException e) { - log.error("Failed to parse major version from server version: " + version, e); throw new SQLException("Failed to parse major version from server version: " + version, ExceptionUtils.SQL_STATE_CLIENT_ERROR, e); } } @@ -1332,11 +1439,11 @@ public ResultSet getClientInfoProperties() throws SQLException { @Override public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException { String sql = "SELECT " + - "NULL AS FUNCTION_CAT, " + - "NULL AS FUNCTION_SCHEM, " + - "name AS FUNCTION_NAME, " + + "NULL::Nullable(String) AS FUNCTION_CAT, " + + "NULL::Nullable(String) AS FUNCTION_SCHEM, " + + "name::Nullable(String) AS FUNCTION_NAME, " + "concat(description, '(', origin, ')') AS REMARKS, " + - java.sql.DatabaseMetaData.functionResultUnknown + " AS FUNCTION_TYPE, " + + java.sql.DatabaseMetaData.functionResultUnknown + "::Int16 AS FUNCTION_TYPE, " + "name AS SPECIFIC_NAME " + "FROM system.functions " + "WHERE name LIKE '" + (functionNamePattern == null ? "%" : functionNamePattern) + "'"; @@ -1354,18 +1461,18 @@ public ResultSet getFunctionColumns(String catalog, String schemaPattern, String "'' AS FUNCTION_SCHEM, " + "'' AS FUNCTION_NAME, " + "'' AS COLUMN_NAME, " + - "0 AS COLUMN_TYPE, " + - "0 AS DATA_TYPE, " + + "0::Int16 AS COLUMN_TYPE, " + + "0::Int32 AS DATA_TYPE, " + "'' AS TYPE_NAME, " + - "0 AS PRECISION, " + - "0 AS LENGTH, " + - "0 AS SCALE, " + - "0 AS RADIX, " + - "0 AS NULLABLE, " + + "0::Int32 AS PRECISION, " + + "0::Int32 AS LENGTH, " + + "0::Int16 AS SCALE, " + + "0::Int16 AS RADIX, " + + "0::Int16 AS NULLABLE, " + "'' AS REMARKS, " + - "0 AS CHAR_OCTET_LENGTH, " + - "0 AS ORDINAL_POSITION, " + - "0 AS IS_NULLABLE, " + + "0::Int32 AS CHAR_OCTET_LENGTH, " + + "0::Int32 AS ORDINAL_POSITION, " + + "'' AS IS_NULLABLE, " + "'' AS SPECIFIC_NAME " + "LIMIT 0"; @@ -1383,13 +1490,13 @@ public ResultSet getPseudoColumns(String catalog, String schemaPattern, String t "'' AS TABLE_SCHEM, " + "'' AS TABLE_NAME, " + "'' AS COLUMN_NAME, " + - "0 AS DATA_TYPE, " + - "0 AS COLUMN_SIZE, " + - "0 AS DECIMAL_DIGITS, " + - "0 AS NUM_PREC_RADIX, " + + "0::Int32 AS DATA_TYPE, " + + "0::Int32 AS COLUMN_SIZE, " + + "0::Int32 AS DECIMAL_DIGITS, " + + "0::Int32 AS NUM_PREC_RADIX, " + "'' AS COLUMN_USAGE, " + "'' AS REMARKS, " + - "0 AS CHAR_OCTET_LENGTH, " + + "0::Int32 AS CHAR_OCTET_LENGTH, " + "'' AS IS_NULLABLE " + " LIMIT 0"; diff --git a/jdbc-v2/src/test/java/com/clickhouse/jdbc/DataTypeTests.java b/jdbc-v2/src/test/java/com/clickhouse/jdbc/DataTypeTests.java index e2ebe772e..9693a9e06 100644 --- a/jdbc-v2/src/test/java/com/clickhouse/jdbc/DataTypeTests.java +++ b/jdbc-v2/src/test/java/com/clickhouse/jdbc/DataTypeTests.java @@ -21,6 +21,7 @@ import java.sql.JDBCType; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.sql.Timestamp; @@ -30,8 +31,11 @@ import java.time.OffsetDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Arrays; import java.util.GregorianCalendar; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Random; @@ -120,10 +124,10 @@ public void testIntegerTypes() throws SQLException { try (Statement stmt = conn.createStatement()) { try (ResultSet rs = stmt.executeQuery("SELECT * FROM test_integers ORDER BY order")) { assertTrue(rs.next()); - assertEquals(rs.getByte("int8"), -128); - assertEquals(rs.getShort("int16"), -32768); - assertEquals(rs.getInt("int32"), -2147483648); - assertEquals(rs.getLong("int64"), -9223372036854775808L); + assertEquals(rs.getByte("int8"), Byte.MIN_VALUE); + assertEquals(rs.getShort("int16"), Short.MIN_VALUE); + assertEquals(rs.getInt("int32"), Integer.MIN_VALUE); + assertEquals(rs.getLong("int64"), Long.MIN_VALUE); assertEquals(rs.getBigDecimal("int128"), new BigDecimal("-170141183460469231731687303715884105728")); assertEquals(rs.getBigDecimal("int256"), new BigDecimal("-57896044618658097711785492504343953926634992332820282019728792003956564819968")); assertEquals(rs.getShort("uint8"), 0); @@ -134,10 +138,10 @@ public void testIntegerTypes() throws SQLException { assertEquals(rs.getBigDecimal("uint256"), new BigDecimal("0")); assertTrue(rs.next()); - assertEquals(rs.getByte("int8"), 127); - assertEquals(rs.getShort("int16"), 32767); - assertEquals(rs.getInt("int32"), 2147483647); - assertEquals(rs.getLong("int64"), 9223372036854775807L); + assertEquals(rs.getByte("int8"), Byte.MAX_VALUE); + assertEquals(rs.getShort("int16"), Short.MAX_VALUE); + assertEquals(rs.getInt("int32"), Integer.MAX_VALUE); + assertEquals(rs.getLong("int64"), Long.MAX_VALUE); assertEquals(rs.getBigDecimal("int128"), new BigDecimal("170141183460469231731687303715884105727")); assertEquals(rs.getBigDecimal("int256"), new BigDecimal("57896044618658097711785492504343953926634992332820282019728792003956564819967")); assertEquals(rs.getShort("uint8"), 255); @@ -171,10 +175,10 @@ public void testIntegerTypes() throws SQLException { try (Statement stmt = conn.createStatement()) { try (ResultSet rs = stmt.executeQuery("SELECT * FROM test_integers ORDER BY order")) { assertTrue(rs.next()); - assertEquals(rs.getObject("int8"), -128); - assertEquals(rs.getObject("int16"), -32768); - assertEquals(rs.getObject("int32"), -2147483648); - assertEquals(rs.getObject("int64"), -9223372036854775808L); + assertEquals(rs.getObject("int8"), Byte.MIN_VALUE); + assertEquals(rs.getObject("int16"), Short.MIN_VALUE); + assertEquals(rs.getObject("int32"), Integer.MIN_VALUE); + assertEquals(rs.getObject("int64"), Long.MIN_VALUE); assertEquals(rs.getObject("int128"), new BigInteger("-170141183460469231731687303715884105728")); assertEquals(rs.getObject("int256"), new BigInteger("-57896044618658097711785492504343953926634992332820282019728792003956564819968")); assertEquals(rs.getObject("uint8"), Short.valueOf("0")); @@ -185,10 +189,10 @@ public void testIntegerTypes() throws SQLException { assertEquals(rs.getObject("uint256"), new BigInteger("0")); assertTrue(rs.next()); - assertEquals(rs.getObject("int8"), 127); - assertEquals(rs.getObject("int16"), 32767); - assertEquals(rs.getObject("int32"), 2147483647); - assertEquals(rs.getObject("int64"), 9223372036854775807L); + assertEquals(rs.getObject("int8"), Byte.MAX_VALUE); + assertEquals(rs.getObject("int16"), Short.MAX_VALUE); + assertEquals(rs.getObject("int32"), Integer.MAX_VALUE); + assertEquals(rs.getObject("int64"), Long.MAX_VALUE); assertEquals(rs.getObject("int128"), new BigInteger("170141183460469231731687303715884105727")); assertEquals(rs.getObject("int256"), new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564819967")); assertEquals(rs.getObject("uint8"), Short.valueOf("255")); @@ -199,10 +203,10 @@ public void testIntegerTypes() throws SQLException { assertEquals(rs.getObject("uint256"), new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639935")); assertTrue(rs.next()); - assertEquals(rs.getObject("int8"), int8); - assertEquals(rs.getObject("int16"), int16); - assertEquals(rs.getObject("int32"), int32); - assertEquals(rs.getObject("int64"), int64); + assertEquals(rs.getObject("int8"), (byte)int8); + assertEquals(rs.getObject("int16"), (short)int16); + assertEquals(rs.getObject("int32"), (int)int32); + assertEquals(rs.getObject("int64"), (long)int64); assertEquals(rs.getObject("int128"), int128); assertEquals(rs.getObject("int256"), int256); assertEquals(rs.getObject("uint8"), uint8); @@ -218,6 +222,78 @@ public void testIntegerTypes() throws SQLException { } } + @Test(groups = { "integration" }) + public void testUnsignedIntegerTypes() throws Exception { + Random rand = new Random(); + runQuery("CREATE TABLE test_unsigned_integers (order Int8, " + + "uint8 Nullable(UInt8), " + + "uint16 Nullable(UInt16), " + + "uint32 Nullable(UInt32), " + + "uint64 Nullable(UInt64), " + + "uint128 Nullable(UInt128), " + + "uint256 Nullable(UInt256)" + + ") ENGINE = MergeTree ORDER BY ()"); + + // Insert null values + insertData("INSERT INTO test_unsigned_integers VALUES ( 1, " + + "NULL, NULL, NULL, NULL, NULL, NULL)"); + + // Insert minimum values + insertData("INSERT INTO test_unsigned_integers VALUES ( 2, " + + "0, 0, 0, 0, 0, 0)"); + + // Insert random values + int uint8 = rand.nextInt(256); + int uint16 = rand.nextInt(65536); + long uint32 = rand.nextLong() & 0xFFFFFFFFL; + long uint64 = rand.nextLong() & 0xFFFFFFFFFFFFL; + BigInteger uint128 = new BigInteger(38, rand); + BigInteger uint256 = new BigInteger(77, rand); + insertData("INSERT INTO test_unsigned_integers VALUES ( 3, " + + uint8 + ", " + uint16 + ", " + uint32 + ", " + uint64 + ", " + uint128 + ", " + uint256 + ")"); + + try (Connection conn = getJdbcConnection(); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT uint8, uint16, uint32, uint64, uint128, uint256 FROM test_unsigned_integers ORDER BY order")) { + + List> expectedTypes = Arrays.asList( + Short.class, Integer.class, Long.class, BigInteger.class, BigInteger.class, BigInteger.class); + List> actualTypes = new ArrayList<>(); + ResultSetMetaData rsmd = rs.getMetaData(); + for (int i = 0; i < rsmd.getColumnCount(); i++) { + actualTypes.add(Class.forName(rsmd.getColumnClassName(i + 1))); + } + assertEquals(actualTypes, expectedTypes); + + + assertTrue(rs.next()); + assertEquals((Short) rs.getObject("uint8"), null); + assertEquals((Integer) rs.getObject("uint16"), null); + assertEquals((Long) rs.getObject("uint32"), null); + assertEquals((BigInteger) rs.getObject("uint64"), null); + assertEquals((BigInteger) rs.getObject("uint128"), null); + assertEquals((BigInteger) rs.getObject("uint256"), null); + + assertTrue(rs.next()); + assertEquals((Short) rs.getObject("uint8"), (byte) 0); + assertEquals((Integer) rs.getObject("uint16"), (short) 0); + assertEquals((Long) rs.getObject("uint32"), 0); + assertEquals((BigInteger) rs.getObject("uint64"), BigInteger.ZERO); + assertEquals((BigInteger) rs.getObject("uint128"), BigInteger.ZERO); + assertEquals((BigInteger) rs.getObject("uint256"), BigInteger.ZERO); + + assertTrue(rs.next()); + assertEquals(((Short) rs.getObject("uint8")).intValue(), uint8); + assertEquals((Integer) rs.getObject("uint16"), uint16); + assertEquals((Long) rs.getObject("uint32"), uint32); + assertEquals((BigInteger) rs.getObject("uint64"), BigInteger.valueOf(uint64)); + assertEquals((BigInteger) rs.getObject("uint128"), uint128); + assertEquals((BigInteger) rs.getObject("uint256"), uint256); + + assertFalse(rs.next()); + } + } + @Test(groups = { "integration" }) public void testDecimalTypes() throws SQLException { runQuery("CREATE TABLE test_decimals (order Int8, " diff --git a/jdbc-v2/src/test/java/com/clickhouse/jdbc/metadata/DatabaseMetaDataTest.java b/jdbc-v2/src/test/java/com/clickhouse/jdbc/metadata/DatabaseMetaDataTest.java index 8c6e8e116..029202ff2 100644 --- a/jdbc-v2/src/test/java/com/clickhouse/jdbc/metadata/DatabaseMetaDataTest.java +++ b/jdbc-v2/src/test/java/com/clickhouse/jdbc/metadata/DatabaseMetaDataTest.java @@ -11,23 +11,95 @@ import org.testng.annotations.Test; import java.sql.Connection; +import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.ResultSetMetaData; +import java.sql.SQLException; import java.sql.Types; -import java.sql.DatabaseMetaData; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Properties; -import static org.testng.Assert.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; @Test(groups = { "integration" }) public class DatabaseMetaDataTest extends JdbcIntegrationTest { @Test(groups = { "integration" }) public void testGetColumns() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + + + try (ResultSet rs = dbmd.getColumns(null, ClickHouseServerForTest.getDatabase(), "system.numbers" + , null)) { + + List expectedColumnNames = Arrays.asList( + "TABLE_CAT", + "TABLE_SCHEM", + "TABLE_NAME", + "COLUMN_NAME", + "DATA_TYPE", + "TYPE_NAME", + "COLUMN_SIZE", + "BUFFER_LENGTH", + "DECIMAL_DIGITS", + "NUM_PREC_RADIX", + "NULLABLE", + "REMARKS", + "COLUMN_DEF", + "SQL_DATA_TYPE", + "SQL_DATETIME_SUB", + "CHAR_OCTET_LENGTH", + "ORDINAL_POSITION", + "IS_NULLABLE", + "SCOPE_CATALOG", + "SCOPE_SCHEMA", + "SCOPE_TABLE", + "SOURCE_DATA_TYPE", + "IS_AUTOINCREMENT", + "IS_GENERATEDCOLUMN" + ); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.INTEGER, + Types.VARCHAR, + Types.INTEGER, + Types.INTEGER, + Types.INTEGER, + Types.INTEGER, + Types.INTEGER, + Types.VARCHAR, + Types.VARCHAR, + Types.INTEGER, + Types.INTEGER, + Types.INTEGER, + Types.INTEGER, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.SMALLINT, + Types.VARCHAR, + Types.VARCHAR + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + } + } + } + @Test(groups = { "integration" }) + public void testGetColumnsWithTable() throws Exception { try (Connection conn = getJdbcConnection()) { final String tableName = "test_get_columns_1"; conn.createStatement().execute("DROP TABLE IF EXISTS " + tableName); @@ -92,7 +164,32 @@ public void testGetColumns() throws Exception { public void testGetTables() throws Exception { try (Connection conn = getJdbcConnection()) { DatabaseMetaData dbmd = conn.getMetaData(); + List expectedColumnNames = Arrays.asList( + "TABLE_CAT", + "TABLE_SCHEM", + "TABLE_NAME", + "TABLE_TYPE", + "REMARKS", + "TYPE_CAT", + "TYPE_SCHEM", + "TYPE_NAME", + "SELF_REFERENCING_COL_NAME", + "REF_GENERATION"); + + List expectedTableTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR); + ResultSet rs = dbmd.getTables("system", null, "numbers", null); + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedTableTypes); assertTrue(rs.next()); assertEquals(rs.getString("TABLE_NAME"), "numbers"); assertEquals(rs.getString("TABLE_TYPE"), "SYSTEM TABLE"); @@ -225,15 +322,57 @@ public void testGetTypeInfo() throws Exception { try (Connection conn = getJdbcConnection()) { DatabaseMetaData dbmd = conn.getMetaData(); try (ResultSet rs = dbmd.getTypeInfo()) { + List expectedColumnNames = Arrays.asList( + "TYPE_NAME", + "DATA_TYPE", + "PRECISION", + "LITERAL_PREFIX", + "LITERAL_SUFFIX", + "CREATE_PARAMS", + "NULLABLE", + "CASE_SENSITIVE", + "SEARCHABLE", + "UNSIGNED_ATTRIBUTE", + "FIXED_PREC_SCALE", + "AUTO_INCREMENT", + "LOCAL_TYPE_NAME", + "MINIMUM_SCALE", + "MAXIMUM_SCALE", + "SQL_DATA_TYPE", + "SQL_DATETIME_SUB", + "NUM_PREC_RADIX" + ); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.INTEGER, + Types.INTEGER, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.SMALLINT, + Types.BOOLEAN, + Types.SMALLINT, + Types.BOOLEAN, + Types.BOOLEAN, + Types.BOOLEAN, + Types.VARCHAR, + Types.SMALLINT, + Types.SMALLINT, + Types.INTEGER, + Types.INTEGER, + Types.INTEGER + ); + + + // check type match with int count = 0; ResultSetMetaData rsMetaData = rs.getMetaData(); - assertTrue(rsMetaData.getColumnCount() >= 18, "Expected at least 18 columns in getTypeInfo result set"); - assertEquals(rsMetaData.getColumnType(2), Types.INTEGER); - assertEquals(rsMetaData.getColumnType(7), Types.INTEGER); + assertProcedureColumns(rsMetaData, expectedColumnNames, expectedColumnTypes); + while (rs.next()) { count++; ClickHouseDataType dataType = ClickHouseDataType.of( rs.getString("TYPE_NAME")); - System.out.println("> " + dataType); assertEquals(ClickHouseDataType.of(rs.getString(1)), dataType); assertEquals(rs.getInt("DATA_TYPE"), (int) JdbcUtils.convertToSqlType(dataType).getVendorTypeNumber(), @@ -282,17 +421,94 @@ public void testGetFunctions() throws Exception { try (Connection conn = getJdbcConnection()) { DatabaseMetaData dbmd = conn.getMetaData(); try (ResultSet rs = dbmd.getFunctions(null, null, "mapContains")) { + + List expectedColumnNames = Arrays.asList( + "FUNCTION_CAT", + "FUNCTION_SCHEM", + "FUNCTION_NAME", + "REMARKS", + "FUNCTION_TYPE", + "SPECIFIC_NAME" + ); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.SMALLINT, + Types.VARCHAR + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + assertTrue(rs.next()); assertNull(rs.getString("FUNCTION_CAT")); assertNull(rs.getString("FUNCTION_SCHEM")); assertEquals(rs.getString("FUNCTION_NAME"), "mapContains"); - assertTrue(rs.getString("REMARKS").startsWith("Checks whether the map has the specified key")); + assertFalse(rs.getString("REMARKS").isEmpty()); assertEquals(rs.getShort("FUNCTION_TYPE"), DatabaseMetaData.functionResultUnknown); assertEquals(rs.getString("SPECIFIC_NAME"), "mapContains"); } } } + @Test(groups = { "integration" }) + public void testGetFunctionColumns() throws Exception { + if (ClickHouseVersion.of(getServerVersion()).check("(,23.8]")) { + return; // Illegal column Int8 of argument of function concat. (ILLEGAL_COLUMN) TODO: fix in JDBC + } + + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + try (ResultSet rs = dbmd.getFunctionColumns(null, null, "mapContains", null)) { + + List expectedColumnNames = Arrays.asList( + "FUNCTION_CAT", + "FUNCTION_SCHEM", + "FUNCTION_NAME", + "COLUMN_NAME", + "COLUMN_TYPE", + "DATA_TYPE", + "TYPE_NAME", + "PRECISION", + "LENGTH", + "SCALE", + "RADIX", + "NULLABLE", + "REMARKS", + "CHAR_OCTET_LENGTH", + "ORDINAL_POSITION", + "IS_NULLABLE", + "SPECIFIC_NAME" + ); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.SMALLINT, + Types.INTEGER, + Types.VARCHAR, + Types.INTEGER, + Types.INTEGER, + Types.SMALLINT, + Types.SMALLINT, + Types.SMALLINT, + Types.VARCHAR, + Types.INTEGER, + Types.INTEGER, + Types.VARCHAR, + Types.VARCHAR + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + + } + } + } + @Test(groups = { "integration" }) public void testGetClientInfoProperties() throws Exception { try (Connection conn = getJdbcConnection()) { @@ -319,12 +535,596 @@ public void testGetDriverVersion() throws Exception { } - @Test(groups = { "integration" }) - public void testGetIndexInfo() throws Exception { + @Test(groups = {"integration"}) + public void testGetIndexInfoColumnType() throws Exception { + try (Connection conn = getJdbcConnection()) { DatabaseMetaData dbmd = conn.getMetaData(); - ResultSet rs = dbmd.getIndexInfo(null, null, "numbers", false, false); - assertFalse(rs.next()); + + List expectedColumnNames = Arrays.asList("TABLE_CAT", + "TABLE_SCHEM", + "TABLE_NAME", + "NON_UNIQUE", + "INDEX_QUALIFIER", + "INDEX_NAME", + "TYPE", + "ORDINAL_POSITION", + "COLUMN_NAME", + "ASC_OR_DESC", + "CARDINALITY", + "PAGES", + "FILTER_CONDITION"); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.BOOLEAN, + Types.VARCHAR, + Types.VARCHAR, + Types.SMALLINT, + Types.SMALLINT, + Types.VARCHAR, + Types.VARCHAR, + Types.BIGINT, + Types.BIGINT, + Types.VARCHAR + ); + + ResultSet rs = dbmd.getIndexInfo(null, null, null, false, false); + ResultSetMetaData rsmd = rs.getMetaData(); + assertProcedureColumns(rsmd, expectedColumnNames, expectedColumnTypes); + } + } + + @Test(groups = {"integration"}) + public void testGetProcedures() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + List columnNames = Arrays.asList("PROCEDURE_CAT", "PROCEDURE_SCHEM", "PROCEDURE_NAME", "RESERVED1", + "RESERVED2", "RESERVED3", "REMARKS", "PROCEDURE_TYPE", "SPECIFIC_NAME"); + List columnTypes = Arrays.asList(Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.SMALLINT, + Types.SMALLINT, Types.SMALLINT, Types.VARCHAR, Types.SMALLINT, Types.VARCHAR); + + ResultSet rs = dbmd.getProcedures(null, null, null); + ResultSetMetaData rsmd = rs.getMetaData(); + assertProcedureColumns(rsmd, columnNames, columnTypes); + } + } + + + @Test(groups = {"integration"}) + public void testGetProceduresColumnType() throws Exception { + + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + + List expectedColumnNames = Arrays.asList("PROCEDURE_CAT", + "PROCEDURE_SCHEM", + "PROCEDURE_NAME", + "COLUMN_NAME", + "COLUMN_TYPE", + "DATA_TYPE", + "TYPE_NAME", + "PRECISION", + "LENGTH", + "SCALE", + "RADIX", + "NULLABLE", + "REMARKS", + "COLUMN_DEF", + "SQL_DATA_TYPE", + "SQL_DATETIME_SUB", + "CHAR_OCTET_LENGTH", + "ORDINAL_POSITION", + "IS_NULLABLE", + "SPECIFIC_NAME"); + List columnTypes = Arrays.asList(Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.SMALLINT, + Types.INTEGER, + Types.VARCHAR, + Types.INTEGER, + Types.INTEGER, + Types.SMALLINT, + Types.SMALLINT, + Types.SMALLINT, + Types.VARCHAR, + Types.VARCHAR, + Types.INTEGER, + Types.INTEGER, + Types.INTEGER, + Types.INTEGER, + Types.VARCHAR, + Types.VARCHAR); + ResultSetMetaData rsmd = dbmd.getProcedureColumns(null, null, null, null).getMetaData(); + assertProcedureColumns(rsmd, expectedColumnNames, columnTypes); + } + } + + + @Test(groups = {"integration"}) + public void testGetColumnPrivileges() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getColumnPrivileges(null, null, null, null); + + List expectedColumnNames = Arrays.asList("TABLE_CAT", + "TABLE_SCHEM", + "TABLE_NAME", + "COLUMN_NAME", + "GRANTOR", + "GRANTEE", + "PRIVILEGE", + "IS_GRANTABLE"); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + } + } + + + @Test(groups = {"integration"}) + public void testGetTablePrivileges() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getTablePrivileges(null, null, null); + + List expectedColumnNames = Arrays.asList("TABLE_CAT", + "TABLE_SCHEM", + "TABLE_NAME", + "GRANTOR", + "GRANTEE", + "PRIVILEGE", + "IS_GRANTABLE"); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + } + } + + @Test(groups = {"integration"}) + public void testGetVersionColumnsColumns() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getVersionColumns(null, null, null); + + List expectedColumnNames = Arrays.asList("SCOPE", + "COLUMN_NAME", + "DATA_TYPE", + "TYPE_NAME", + "COLUMN_SIZE", + "BUFFER_LENGTH", + "DECIMAL_DIGITS", + "PSEUDO_COLUMN"); + + List expectedColumnTypes = Arrays.asList( + Types.SMALLINT, + Types.VARCHAR, + Types.INTEGER, + Types.VARCHAR, + Types.INTEGER, + Types.INTEGER, + Types.SMALLINT, + Types.SMALLINT + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + } + } + + + @Test(groups = {"integration"}) + public void testGetPrimaryKeysColumns() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getPrimaryKeys(null, null, null); + + List expectedColumnNames = Arrays.asList("TABLE_CAT", + "TABLE_SCHEM", + "TABLE_NAME", + "COLUMN_NAME", + "KEY_SEQ", + "PK_NAME"); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.SMALLINT, + Types.VARCHAR + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + } + } + + @Test(groups = {"integration"}) + public void testGetImportedKeys() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getImportedKeys(null, null, null); + + List expectedColumnNames = Arrays.asList("PKTABLE_CAT", + "PKTABLE_SCHEM", + "PKTABLE_NAME", + "PKCOLUMN_NAME", + "FKTABLE_CAT", + "FKTABLE_SCHEM", + "FKTABLE_NAME", + "FKCOLUMN_NAME", + "KEY_SEQ", + "UPDATE_RULE", + "DELETE_RULE", + "FK_NAME", + "PK_NAME", + "DEFERRABILITY"); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.SMALLINT, + Types.SMALLINT, + Types.SMALLINT, + Types.VARCHAR, + Types.VARCHAR, + Types.SMALLINT + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + } + } + + @Test(groups = {"integration"}) + public void testGetExportedKeys() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getExportedKeys(null, null, null); + + List expectedColumnNames = Arrays.asList("PKTABLE_CAT", + "PKTABLE_SCHEM", + "PKTABLE_NAME", + "PKCOLUMN_NAME", + "FKTABLE_CAT", + "FKTABLE_SCHEM", + "FKTABLE_NAME", + "FKCOLUMN_NAME", + "KEY_SEQ", + "UPDATE_RULE", + "DELETE_RULE", + "FK_NAME", + "PK_NAME", + "DEFERRABILITY"); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.SMALLINT, + Types.SMALLINT, + Types.SMALLINT, + Types.VARCHAR, + Types.VARCHAR, + Types.SMALLINT + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + } + } + + + @Test(groups = {"integration"}) + public void testGetCrossReference() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getCrossReference(null, null, null, null, null, null); + + List expectedColumnNames = Arrays.asList("PKTABLE_CAT", + "PKTABLE_SCHEM", + "PKTABLE_NAME", + "PKCOLUMN_NAME", + "FKTABLE_CAT", + "FKTABLE_SCHEM", + "FKTABLE_NAME", + "FKCOLUMN_NAME", + "KEY_SEQ", + "UPDATE_RULE", + "DELETE_RULE", + "FK_NAME", + "PK_NAME", + "DEFERRABILITY"); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.SMALLINT, + Types.SMALLINT, + Types.SMALLINT, + Types.VARCHAR, + Types.VARCHAR, + Types.SMALLINT + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + } + } + + @Test(groups = {"integration"}) + public void testGetUDTs() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getUDTs(null, null, null, null); + + List expectedColumnNames = Arrays.asList("TYPE_CAT", + "TYPE_SCHEM", + "TYPE_NAME", + "CLASS_NAME", + "DATA_TYPE", + "REMARKS", + "BASE_TYPE"); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.INTEGER, + Types.VARCHAR, + Types.SMALLINT + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + } + } + + + @Test(groups = {"integration"}) + public void testGetSuperTypes() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getSuperTypes(null, null, null); + + List expectedColumnNames = Arrays.asList("TYPE_CAT", + "TYPE_SCHEM", + "TYPE_NAME", + "SUPERTYPE_CAT", + "SUPERTYPE_SCHEM", + "SUPERTYPE_NAME"); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + } + } + + @Test(groups = {"integration"}) + public void testGetSuperTables() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getSuperTables(null, null, null); + + List expectedColumnNames = Arrays.asList("TABLE_CAT", + "TABLE_SCHEM", + "TABLE_NAME", + "SUPERTABLE_NAME"); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + } + } + + + @Test(groups = {"integration"}) + public void testGetBestRowIdentifier() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getBestRowIdentifier(null, null, null, 0, true); + + List expectedColumnNames = Arrays.asList("SCOPE", + "COLUMN_NAME", + "DATA_TYPE", + "TYPE_NAME", + "COLUMN_SIZE", + "BUFFER_LENGTH", + "DECIMAL_DIGITS", + "PSEUDO_COLUMN"); + + List expectedColumnTypes = Arrays.asList( + Types.SMALLINT, + Types.VARCHAR, + Types.INTEGER, + Types.VARCHAR, + Types.INTEGER, + Types.INTEGER, + Types.SMALLINT, + Types.SMALLINT + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + } + } + + + @Test(groups = {"integration"}) + public void testGetAttributes() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getAttributes(null, null, null, null); + + List expectedColumnNames = Arrays.asList("TYPE_CAT", + "TYPE_SCHEM", + "TYPE_NAME", + "ATTR_NAME", + "DATA_TYPE", + "ATTR_TYPE_NAME", + "ATTR_SIZE", + "DECIMAL_DIGITS", + "NUM_PREC_RADIX", + "NULLABLE", + "REMARKS", + "ATTR_DEF", + "SQL_DATA_TYPE", + "SQL_DATETIME_SUB", + "CHAR_OCTET_LENGTH", + "ORDINAL_POSITION", + "IS_NULLABLE", + "SCOPE_CATALOG", + "SCOPE_SCHEMA", + "SCOPE_TABLE", + "SOURCE_DATA_TYPE"); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.INTEGER, + Types.VARCHAR, + Types.INTEGER, + Types.INTEGER, + Types.INTEGER, + Types.INTEGER, + Types.VARCHAR, + Types.VARCHAR, + Types.INTEGER, + Types.INTEGER, + Types.INTEGER, + Types.INTEGER, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.SMALLINT + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + } + } + + + @Test(groups = {"integration"}) + public void testGetPseudoColumns() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getPseudoColumns(null, null, null, null); + + List expectedColumnNames = Arrays.asList("TABLE_CAT", + "TABLE_SCHEM", + "TABLE_NAME", + "COLUMN_NAME", + "DATA_TYPE", + "COLUMN_SIZE", + "DECIMAL_DIGITS", + "NUM_PREC_RADIX", + "COLUMN_USAGE", + "REMARKS", + "CHAR_OCTET_LENGTH", + "IS_NULLABLE"); + + List expectedColumnTypes = Arrays.asList( + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.VARCHAR, + Types.INTEGER, + Types.INTEGER, + Types.INTEGER, + Types.INTEGER, + Types.VARCHAR, + Types.VARCHAR, + Types.INTEGER, + Types.VARCHAR + ); + + assertProcedureColumns(rs.getMetaData(), expectedColumnNames, expectedColumnTypes); + } + } + + private void assertProcedureColumns(ResultSetMetaData rsmd, List expectedColumnNames, List expectedColumnTypes) throws SQLException { + int columnCount = rsmd.getColumnCount(); + assertEquals(columnCount, expectedColumnNames.size(), "number of columns"); + for (int i = 1; i <= columnCount; i++) { + String columnName = rsmd.getColumnName(i); + int columnType = rsmd.getColumnType(i); + assertEquals(columnName, expectedColumnNames.get(i - 1), "Column name mismatch"); + assertEquals(columnType, expectedColumnTypes.get(i - 1), "Column type mismatch for column name " + columnName + " (" + i + ")"); + } + } + + + + @Test(groups = {"integration"}) + public void testGetDatabaseMajorVersion() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + int majorVersion = dbmd.getDatabaseMajorVersion(); + String version = getServerVersion(); + int majorVersionOfServer = Integer.parseInt(version.split("\\.")[0]); + assertEquals(majorVersion, majorVersionOfServer, "Major version"); + } + } + + + @Test(groups = {"integration"}) + public void testGetDatabaseMinorVersion() throws Exception { + try (Connection conn = getJdbcConnection()) { + DatabaseMetaData dbmd = conn.getMetaData(); + int minorVersion = dbmd.getDatabaseMinorVersion(); + String version = getServerVersion(); + int minorVersionOfServer = Integer.parseInt(version.split("\\.")[1]); + assertEquals(minorVersion, minorVersionOfServer, "Minor version"); } } } diff --git a/jdbc-v2/src/test/java/com/clickhouse/jdbc/metadata/ResultSetMetaDataImplTest.java b/jdbc-v2/src/test/java/com/clickhouse/jdbc/metadata/ResultSetMetaDataImplTest.java index d7387e8af..f7bfee463 100644 --- a/jdbc-v2/src/test/java/com/clickhouse/jdbc/metadata/ResultSetMetaDataImplTest.java +++ b/jdbc-v2/src/test/java/com/clickhouse/jdbc/metadata/ResultSetMetaDataImplTest.java @@ -58,9 +58,9 @@ public void testGetColumnTypeIntegers() throws Exception { ResultSet rs = stmt.executeQuery("SELECT toInt8(1), toInt16(1), toInt32(1), toInt64(1) AS a"); ResultSetMetaData rsmd = rs.getMetaData(); assertEquals(rsmd.getColumnType(1), Types.TINYINT); - assertEquals(rsmd.getColumnClassName(1), Integer.class.getName()); + assertEquals(rsmd.getColumnClassName(1), Byte.class.getName()); assertEquals(rsmd.getColumnType(2), Types.SMALLINT); - assertEquals(rsmd.getColumnClassName(2), Integer.class.getName()); + assertEquals(rsmd.getColumnClassName(2), Short.class.getName()); assertEquals(rsmd.getColumnType(3), Types.INTEGER); assertEquals(rsmd.getColumnClassName(3), Integer.class.getName()); assertEquals(rsmd.getColumnType(4), Types.BIGINT);