1111import com .clickhouse .jdbc .ResultSetImpl ;
1212import com .clickhouse .jdbc .internal .ExceptionUtils ;
1313import com .clickhouse .jdbc .internal .JdbcUtils ;
14- import com .clickhouse .jdbc .internal .MetadataResultSet ;
1514import com .clickhouse .logging .Logger ;
1615import com .clickhouse .logging .LoggerFactory ;
1716
2221import java .sql .SQLException ;
2322import java .sql .SQLFeatureNotSupportedException ;
2423import java .sql .SQLType ;
24+ import java .sql .Types ;
2525import java .util .Arrays ;
2626
2727public class DatabaseMetaDataImpl implements java .sql .DatabaseMetaData , JdbcV2Wrapper {
@@ -222,7 +222,7 @@ public String getStringFunctions() throws SQLException {
222222 public String getSystemFunctions () throws SQLException {
223223 // took from below URL(not from system.functions):
224224 // https://clickhouse.com/docs/en/sql-reference/functions/other-functions/
225- return "bar,basename,blockNumber,blockSerializedSize,blockSize,buildId,byteSize,countDigits,currentDatabase,currentProfiles,currentRoles,currentUser,defaultProfiles,defaultRoles,defaultValueOfArgumentType,defaultValueOfTypeName,dumpColumnStructure,enabledProfiles,enabledRoles,errorCodeToName,filesystemAvailable,filesystemCapacity,filesystemFree,finalizeAggregation,formatReadableQuantity,formatReadableSize,formatReadableTimeDelta,FQDN,getMacro,getServerPort,getSetting,getSizeOfEnumType,greatest,hasColumnInTable,hostName,identity,ifNotFinite,ignore,indexHint,initializeAggregation,initialQueryID,isConstant,isDecimalOverflow,isFinite,isInfinite,isNaN,joinGet,least,MACNumToString,MACStringToNum,MACStringToOUI,materialize,modelEvaluate,neighbor,queryID,randomFixedString,randomPrintableASCII,randomString,randomStringUTF8,replicate,rowNumberInAllBlocks,rowNumberInBlock,runningAccumulate,runningConcurrency,runningDifference,runningDifferenceStartingWithFirstValue,shardCount ,shardNum,sleep,sleepEachRow,tcpPort,throwIf,toColumnTypeName,toTypeName,transform,uptime,version,visibleWidth" ;
225+ return "bar,basename,blockNumber,blockSerializedSize,blockSize,buildId,byteSize,countDigits,currentDatabase,currentProfiles,currentRoles,currentUser,defaultProfiles,defaultRoles,defaultValueOfArgumentType,defaultValueOfTypeName,dumpColumnStructure,enabledProfiles,enabledRoles,errorCodeToName,filesystemAvailable,filesystemCapacity,filesystemFree,finalizeAggregation,formatReadableQuantity,formatReadableSize,formatReadableTimeDelta,FQDN,getMacro,getServerPort,getSetting,getSizeOfEnumType,greatest,hasColumnInTable,hostName,identity,ifNotFinite,ignore,indexHint,initializeAggregation,initialQueryID,isConstant,isDecimalOverflow,isFinite,isInfinite,isNaN,joinGet,least,MACNumToString,MACStringToNum,MACStringToOUI,materialize,modelEvaluate,neighbor,queryID,randomFixedString,randomPrintableASCII,randomString,randomStringUTF8,replicate,rowNumberInAllBlocks,rowNumberInBlock,runningAccumulate,runningConcurrency,runningDifference,runningDifferenceStartingWithFirstValue,shardCount ,shardNum,sleep,sleepEachRow,tcpPort,throwIf,toColumnTypeName,toTypeName,e,uptime,version,visibleWidth" ;
226226 }
227227
228228 @ Override
@@ -830,18 +830,19 @@ public ResultSet getTableTypes() throws SQLException {
830830 }
831831 }
832832
833- private static final ClickHouseColumn DATA_TYPE_COL = ClickHouseColumn .of ("DATA_TYPE" , ClickHouseDataType .Int32 .name ()) ;
833+ private static final int GET_COLUMNS_TYPE_NAME_COL = 6 ;
834+
835+ private static final int GET_COLUMNS_DATA_TYPE_COL = 5 ;
834836 @ Override
835837 @ SuppressWarnings ({"squid:S2095" , "squid:S2077" })
836838 public ResultSet getColumns (String catalog , String schemaPattern , String tableNamePattern , String columnNamePattern ) throws SQLException {
837- //TODO: Best way to convert type to JDBC data type
838839 // TODO: handle useCatalogs == true and return schema catalog name
839- String sql = "SELECT " +
840+ final String sql = "SELECT " +
840841 catalogPlaceholder + " AS TABLE_CAT, " +
841842 "database AS TABLE_SCHEM, " +
842843 "table AS TABLE_NAME, " +
843844 "name AS COLUMN_NAME, " +
844- "system.columns.type AS DATA_TYPE, " +
845+ "toInt32(" + Types . OTHER + ") AS DATA_TYPE, " +
845846 "type AS TYPE_NAME, " +
846847 "toInt32(" + generateSqlTypeSizes ("system.columns.type" ) + ") AS COLUMN_SIZE, " +
847848 "toInt32(0) AS BUFFER_LENGTH, " +
@@ -867,8 +868,9 @@ public ResultSet getColumns(String catalog, String schemaPattern, String tableNa
867868 " AND name LIKE " + SQLUtils .enquoteLiteral (columnNamePattern == null ? "%" : columnNamePattern ) +
868869 " ORDER BY TABLE_SCHEM, TABLE_NAME, ORDINAL_POSITION" ;
869870 try {
870- return new MetadataResultSet ((ResultSetImpl ) connection .createStatement ().executeQuery (sql ))
871- .transform (DATA_TYPE_COL .getColumnName (), DATA_TYPE_COL , DatabaseMetaDataImpl ::columnDataTypeToSqlType );
871+ ResultSetImpl rs = (ResultSetImpl ) connection .createStatement ().executeQuery (sql );
872+ rs .setValueFunction (GET_COLUMNS_DATA_TYPE_COL , GET_COLUMNS_DATA_TYPE_FUNC );
873+ return rs ;
872874 } catch (Exception e ) {
873875 throw ExceptionUtils .toSqlState (e );
874876 }
@@ -887,17 +889,22 @@ private static String generateSqlTypeSizes(String columnName) {
887889 return sql .toString ();
888890 }
889891
890- private static String columnDataTypeToSqlType (String value ) {
891- SQLType type = JdbcUtils .CLICKHOUSE_TYPE_NAME_TO_SQL_TYPE_MAP .get (value );
892- if (type == null ) {
893- try {
894- type = JdbcUtils .convertToSqlType (ClickHouseColumn .of ("v1" , value ).getDataType ());
895- } catch (Exception e ) {
896- log .error ("Failed to convert column data type to SQL type: {}" , value , e );
897- type = JDBCType .OTHER ; // In case of error, return SQL type 0
892+ private static final ClickHouseColumn .ValueFunction GET_COLUMNS_DATA_TYPE_FUNC = dataTypeValueFunction (GET_COLUMNS_TYPE_NAME_COL );
893+
894+ private static ClickHouseColumn .ValueFunction dataTypeValueFunction (int srcColIndex ) {
895+ return row -> {
896+ String typeName = (String ) row [srcColIndex - 1 ];
897+ SQLType type = JdbcUtils .CLICKHOUSE_TYPE_NAME_TO_SQL_TYPE_MAP .get (typeName );
898+ if (type == null ) {
899+ try {
900+ type = JdbcUtils .convertToSqlType (ClickHouseColumn .of ("v1" , typeName ).getDataType ());
901+ } catch (Exception e ) {
902+ log .error ("Failed to convert column data type to SQL type: {}" , typeName , e );
903+ type = JDBCType .OTHER ; // In case of error, return SQL type 0
904+ }
898905 }
899- }
900- return String . valueOf ( type . getVendorTypeNumber ()) ;
906+ return type . getVendorTypeNumber ();
907+ } ;
901908 }
902909
903910 @ Override
@@ -1067,26 +1074,23 @@ public ResultSet getCrossReference(String parentCatalog, String parentSchema, St
10671074 }
10681075 }
10691076
1070- private static final ClickHouseColumn NULLABLE_COL = ClickHouseColumn .of ("NULLABLE" , ClickHouseDataType .Int16 .name ());
1077+ private static final int TYPE_INFO_DATA_TYPE_COL = 2 ;
1078+ private static final int TYPE_INFO_NULLABILITY_COL = 7 ;
10711079 @ Override
10721080 @ SuppressWarnings ({"squid:S2095" })
10731081 public ResultSet getTypeInfo () throws SQLException {
10741082 try {
1075- return new MetadataResultSet ((ResultSetImpl ) connection .createStatement ().executeQuery (DATA_TYPE_INFO_SQL ))
1076- .transform (DATA_TYPE_COL .getColumnName (), DATA_TYPE_COL , DatabaseMetaDataImpl ::dataTypeToSqlTypeInt )
1077- .transform (NULLABLE_COL .getColumnName (), NULLABLE_COL , DatabaseMetaDataImpl ::dataTypeNullability );
1083+ ResultSetImpl rs = (ResultSetImpl ) connection .createStatement ().executeQuery (DATA_TYPE_INFO_SQL );
1084+ rs .setValueFunction (TYPE_INFO_DATA_TYPE_COL , TYPE_INFO_DATA_TYPE_VALUE_FUNC );
1085+ rs .setValueFunction (TYPE_INFO_NULLABILITY_COL , DatabaseMetaDataImpl ::dataTypeNullability );
1086+ return rs ;
10781087 } catch (Exception e ) {
10791088 throw ExceptionUtils .toSqlState (e );
10801089 }
10811090 }
10821091
1083- private static String dataTypeToSqlTypeInt (String type ) {
1084- SQLType sqlType = JdbcUtils .CLICKHOUSE_TYPE_NAME_TO_SQL_TYPE_MAP .get (type );
1085- return sqlType == null ? String .valueOf (JDBCType .OTHER .getVendorTypeNumber ()) :
1086- String .valueOf (sqlType .getVendorTypeNumber ());
1087- }
1088-
1089- private static String dataTypeNullability (String type ) {
1092+ private static String dataTypeNullability (Object [] row ) {
1093+ String type = (String ) row [DATA_TYPE_INFO_SQL_TYPE_NAME_COL - 1 ];
10901094 if (type .equals (ClickHouseDataType .Nullable .name ()) || type .equals (ClickHouseDataType .Dynamic .name ())) {
10911095 return String .valueOf (java .sql .DatabaseMetaData .typeNullable );
10921096 }
@@ -1095,21 +1099,23 @@ private static String dataTypeNullability(String type) {
10951099
10961100 private static final String DATA_TYPE_INFO_SQL = getDataTypeInfoSql ();
10971101
1102+ private static final int DATA_TYPE_INFO_SQL_TYPE_NAME_COL = 13 ;
1103+
10981104 private static String getDataTypeInfoSql () {
10991105 StringBuilder sql = new StringBuilder ("SELECT " +
11001106 "name AS TYPE_NAME, " +
1101- "if(empty(alias_to), name, alias_to) AS DATA_TYPE, " + // passing type name or alias if exists to map then
1107+ "0::Int32 AS DATA_TYPE, " + // passing type name or alias if exists to map then
11021108 "attrs.c2::Nullable(Int32) AS PRECISION, " +
11031109 "NULL::Nullable(String) AS LITERAL_PREFIX, " +
11041110 "NULL::Nullable(String) AS LITERAL_SUFFIX, " +
11051111 "NULL::Nullable(String) AS CREATE_PARAMS, " +
1106- "name AS NULLABLE, " + // passing type name to map for nullable
1112+ "0::Int16 AS NULLABLE, " + // passing type name to map for nullable
11071113 "not(dt.case_insensitive)::Boolean AS CASE_SENSITIVE, " +
11081114 java .sql .DatabaseMetaData .typeSearchable + "::Int16 AS SEARCHABLE, " +
11091115 "not(attrs.c3)::Boolean AS UNSIGNED_ATTRIBUTE, " +
11101116 "false AS FIXED_PREC_SCALE, " +
11111117 "false AS AUTO_INCREMENT, " +
1112- "name AS LOCAL_TYPE_NAME, " +
1118+ "if(empty(alias_to), name, alias_to) AS LOCAL_TYPE_NAME, " +
11131119 "attrs.c4::Nullable(Int16) AS MINIMUM_SCALE, " +
11141120 "attrs.c5::Nullable(Int16) AS MAXIMUM_SCALE, " +
11151121 "0::Nullable(Int32) AS SQL_DATA_TYPE, " +
@@ -1134,6 +1140,8 @@ private static String getDataTypeInfoSql() {
11341140 return sql .toString ();
11351141 }
11361142
1143+ private static final ClickHouseColumn .ValueFunction TYPE_INFO_DATA_TYPE_VALUE_FUNC = dataTypeValueFunction (DATA_TYPE_INFO_SQL_TYPE_NAME_COL );
1144+
11371145 @ Override
11381146 public ResultSet getIndexInfo (String catalog , String schema , String table , boolean unique , boolean approximate ) throws SQLException {
11391147 try {
0 commit comments