diff --git a/src/main/java/org/duckdb/DuckDBDatabaseMetaData.java b/src/main/java/org/duckdb/DuckDBDatabaseMetaData.java index 89bff734..37c6ed37 100644 --- a/src/main/java/org/duckdb/DuckDBDatabaseMetaData.java +++ b/src/main/java/org/duckdb/DuckDBDatabaseMetaData.java @@ -825,7 +825,7 @@ public ResultSet getColumns(String catalogPattern, String schemaPattern, String + "table_catalog AS 'TABLE_CAT', " + "table_schema AS 'TABLE_SCHEM', " + "table_name AS 'TABLE_NAME', " - + "column_name as 'COLUMN_NAME', " + makeDataMap("c.data_type", "DATA_TYPE") + ", " + + "column_name as 'COLUMN_NAME', " + makeDataMap("regexp_replace(c.data_type, '\\(.*\\)', '')", "DATA_TYPE") + ", " + "c.data_type AS 'TYPE_NAME', " + "NULL AS 'COLUMN_SIZE', NULL AS 'BUFFER_LENGTH', " + "numeric_precision AS 'DECIMAL_DIGITS', " diff --git a/src/test/java/org/duckdb/TestDuckDBJDBC.java b/src/test/java/org/duckdb/TestDuckDBJDBC.java index 1d2425e8..cb5d6c6a 100644 --- a/src/test/java/org/duckdb/TestDuckDBJDBC.java +++ b/src/test/java/org/duckdb/TestDuckDBJDBC.java @@ -8,23 +8,8 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.sql.Array; -import java.sql.Blob; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.Date; -import java.sql.Driver; +import java.sql.*; import java.util.concurrent.Future; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Struct; -import java.sql.Time; -import java.sql.Timestamp; -import java.sql.Types; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; @@ -4258,6 +4243,49 @@ public static void test_fractional_time() throws Exception { } } + public static void test_column_metadata() throws Exception { + Map expectedTypes = new HashMap<>(); + expectedTypes.put("bool", JDBCType.BOOLEAN); + expectedTypes.put("tinyint", JDBCType.TINYINT); + expectedTypes.put("smallint", JDBCType.SMALLINT); + expectedTypes.put("int", JDBCType.INTEGER); + expectedTypes.put("bigint", JDBCType.BIGINT); + expectedTypes.put("date", JDBCType.DATE); + expectedTypes.put("time", JDBCType.TIME); + expectedTypes.put("timestamp", JDBCType.TIMESTAMP); + expectedTypes.put("time_tz", JDBCType.TIME_WITH_TIMEZONE); + expectedTypes.put("timestamp_tz", JDBCType.TIMESTAMP_WITH_TIMEZONE); + expectedTypes.put("float", JDBCType.FLOAT); + expectedTypes.put("double", JDBCType.DOUBLE); + expectedTypes.put("varchar", JDBCType.VARCHAR); + expectedTypes.put("blob", JDBCType.BLOB); + expectedTypes.put("bit", JDBCType.BIT); + expectedTypes.put("struct", JDBCType.STRUCT); + expectedTypes.put("struct_of_arrays", JDBCType.STRUCT); + expectedTypes.put("struct_of_fixed_array", JDBCType.STRUCT); + expectedTypes.put("dec_4_1", JDBCType.DECIMAL); + expectedTypes.put("dec_9_4", JDBCType.DECIMAL); + expectedTypes.put("dec_18_6", JDBCType.DECIMAL); + expectedTypes.put("dec38_10", JDBCType.DECIMAL); + + try (Connection conn = DriverManager.getConnection(JDBC_URL)) { + try (Statement stmt = conn.createStatement()) { + stmt.execute("CREATE TABLE test_all_types_metadata AS SELECT * from test_all_types()"); + } + + try (ResultSet rs = conn.getMetaData().getColumns(null, null, "test_all_types_metadata", null)) { + while (rs.next()) { + String column = rs.getString("COLUMN_NAME"); + JDBCType expectedType = expectedTypes.get(column); + if (expectedType == null) { + expectedType = JDBCType.JAVA_OBJECT; + } + assertEquals(rs.getInt("DATA_TYPE"), expectedType.getVendorTypeNumber(), column); + } + } + } + } + public static void main(String[] args) throws Exception { System.exit(runTests(args, TestDuckDBJDBC.class, TestExtensionTypes.class)); } diff --git a/src/test/java/org/duckdb/test/Assertions.java b/src/test/java/org/duckdb/test/Assertions.java index f2d82e68..d7cb3543 100644 --- a/src/test/java/org/duckdb/test/Assertions.java +++ b/src/test/java/org/duckdb/test/Assertions.java @@ -21,9 +21,13 @@ public static void assertFalse(boolean val) throws Exception { } public static void assertEquals(Object actual, Object expected) throws Exception { + assertEquals(actual, expected, ""); + } + public static void assertEquals(Object actual, Object expected, String label) throws Exception { Function getClass = (Object a) -> a == null ? "null" : a.getClass().toString(); - String message = String.format("\"%s\" (of %s) should equal \"%s\" (of %s)", actual, getClass.apply(actual), + String message = label.isEmpty() ? "" : label + ": "; + message += String.format("\"%s\" (of %s) should equal \"%s\" (of %s)", actual, getClass.apply(actual), expected, getClass.apply(expected)); assertTrue(Objects.equals(actual, expected), message); }