package org.mariadb.jdbc; import org.junit.Assume; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import java.sql.*; import static org.junit.Assert.*; public class DatabaseMetadataTest extends BaseTest { /** * Initialisation. * * @throws SQLException exception */ @BeforeClass() public static void initClass() throws SQLException { createTable("dbpk_test", "val varchar(20), id1 int not null, id2 int not null,primary key(id1, id2)", "engine=innodb"); createTable("datetime_test", "dt datetime"); createTable("`manycols`", " `tiny` tinyint(4) DEFAULT NULL," + " `tiny_uns` tinyint(3) unsigned DEFAULT NULL," + " `small` smallint(6) DEFAULT NULL," + " `small_uns` smallint(5) unsigned DEFAULT NULL," + " `medium` mediumint(9) DEFAULT NULL," + " `medium_uns` mediumint(8) unsigned DEFAULT NULL," + " `int_col` int(11) DEFAULT NULL," + " `int_col_uns` int(10) unsigned DEFAULT NULL," + " `big` bigint(20) DEFAULT NULL," + " `big_uns` bigint(20) unsigned DEFAULT NULL," + " `decimal_col` decimal(10,5) DEFAULT NULL," + " `fcol` float DEFAULT NULL," + " `fcol_uns` float unsigned DEFAULT NULL," + " `dcol` double DEFAULT NULL," + " `dcol_uns` double unsigned DEFAULT NULL," + " `date_col` date DEFAULT NULL," + " `time_col` time DEFAULT NULL," + " `timestamp_col` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP," + " `year_col` year(4) DEFAULT NULL," + " `bit_col` bit(5) DEFAULT NULL," + " `char_col` char(5) DEFAULT NULL," + " `varchar_col` varchar(10) DEFAULT NULL," + " `binary_col` binary(10) DEFAULT NULL," + " `varbinary_col` varbinary(10) DEFAULT NULL," + " `tinyblob_col` tinyblob," + " `blob_col` blob," + " `mediumblob_col` mediumblob," + " `longblob_col` longblob," + " `tinytext_col` tinytext," + " `text_col` text," + " `mediumtext_col` mediumtext," + " `longtext_col` longtext" ); createTable("ytab", "y year"); createTable("maxcharlength", "maxcharlength char(1)", "character set utf8"); createTable("conj72", "t tinyint(1)"); } private static void checkType(String name, int actualType, String colName, int expectedType) { if (name.equals(colName)) { assertEquals(actualType, expectedType); } } @Before public void checkSupported() throws SQLException { requireMinimumVersion(5, 1); } @Test public void primaryKeysTest() throws SQLException { DatabaseMetaData dbmd = sharedConnection.getMetaData(); ResultSet rs = dbmd.getPrimaryKeys("testj", null, "dbpk_test"); int counter = 0; while (rs.next()) { counter++; assertEquals("testj", rs.getString("table_cat")); assertEquals(null, rs.getString("table_schem")); assertEquals("dbpk_test", rs.getString("table_name")); assertEquals("id" + counter, rs.getString("column_name")); assertEquals(counter, rs.getShort("key_seq")); } assertEquals(2, counter); } @Test public void primaryKeyTest2() throws SQLException { Statement stmt = sharedConnection.createStatement(); stmt.execute("drop table if exists t2"); stmt.execute("drop table if exists t1"); stmt.execute("CREATE TABLE t1 ( id1 integer, constraint pk primary key(id1))"); stmt.execute("CREATE TABLE t2 (id2a integer, id2b integer, constraint pk primary key(id2a, id2b), " + "constraint fk1 foreign key(id2a) references t1(id1), constraint fk2 foreign key(id2b) " + "references t1(id1))"); DatabaseMetaData dbmd = sharedConnection.getMetaData(); ResultSet rs = dbmd.getPrimaryKeys("testj", null, "t2"); int counter = 0; while (rs.next()) { counter++; assertEquals("testj", rs.getString("table_cat")); assertEquals(null, rs.getString("table_schem")); assertEquals("t2", rs.getString("table_name")); assertEquals(counter, rs.getShort("key_seq")); } assertEquals(2, counter); stmt.execute("drop table if exists t2"); stmt.execute("drop table if exists t1"); } @Test public void datetimeTest() throws SQLException { Statement stmt = sharedConnection.createStatement(); ResultSet rs = stmt.executeQuery("select * from datetime_test"); assertEquals(93, rs.getMetaData().getColumnType(1)); } @Test public void functionColumns() throws SQLException { Statement stmt = sharedConnection.createStatement(); DatabaseMetaData md = sharedConnection.getMetaData(); if (md.getDatabaseMajorVersion() < 5) { return; } else if (md.getDatabaseMajorVersion() == 5 && md.getDatabaseMinorVersion() < 5) { return; } stmt.execute("DROP FUNCTION IF EXISTS hello"); stmt.execute("CREATE FUNCTION hello (s CHAR(20), i int) RETURNS CHAR(50) DETERMINISTIC " + "RETURN CONCAT('Hello, ',s,'!')"); ResultSet rs = sharedConnection.getMetaData().getFunctionColumns(null, null, "hello", null); rs.next(); /* First row is for return value */ assertEquals(rs.getString("FUNCTION_CAT"), sharedConnection.getCatalog()); assertEquals(rs.getString("FUNCTION_SCHEM"), null); assertEquals(rs.getString("COLUMN_NAME"), null); /* No name, since it is return value */ assertEquals(rs.getInt("COLUMN_TYPE"), DatabaseMetaData.functionReturn); assertEquals(rs.getInt("DATA_TYPE"), Types.CHAR); assertEquals(rs.getString("TYPE_NAME"), "char"); rs.next(); assertEquals(rs.getString("COLUMN_NAME"), "s"); /* input parameter 's' (CHAR) */ assertEquals(rs.getInt("COLUMN_TYPE"), DatabaseMetaData.functionColumnIn); assertEquals(rs.getInt("DATA_TYPE"), Types.CHAR); assertEquals(rs.getString("TYPE_NAME"), "char"); rs.next(); assertEquals(rs.getString("COLUMN_NAME"), "i"); /* input parameter 'i' (INT) */ assertEquals(rs.getInt("COLUMN_TYPE"), DatabaseMetaData.functionColumnIn); assertEquals(rs.getInt("DATA_TYPE"), Types.INTEGER); assertEquals(rs.getString("TYPE_NAME"), "int"); stmt.execute("DROP FUNCTION IF EXISTS hello"); } /** * Same as getImportedKeys, with one foreign key in a table in another catalog. */ @Test public void getImportedKeys() throws Exception { Statement st = sharedConnection.createStatement(); st.execute("DROP TABLE IF EXISTS product_order"); st.execute("DROP TABLE IF EXISTS t1.product "); st.execute("DROP TABLE IF EXISTS `cus``tomer`"); st.execute("DROP DATABASE IF EXISTS test1"); st.execute("CREATE DATABASE IF NOT EXISTS t1"); st.execute("CREATE TABLE t1.product ( category INT NOT NULL, id INT NOT NULL, price DECIMAL," + " PRIMARY KEY(category, id) ) ENGINE=INNODB"); st.execute("CREATE TABLE `cus``tomer` (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB"); st.execute("CREATE TABLE product_order (\n" + " no INT NOT NULL AUTO_INCREMENT,\n" + " product_category INT NOT NULL,\n" + " product_id INT NOT NULL,\n" + " customer_id INT NOT NULL,\n" + " PRIMARY KEY(no),\n" + " INDEX (product_category, product_id),\n" + " INDEX (customer_id),\n" + " FOREIGN KEY (product_category, product_id)\n" + " REFERENCES t1.product(category, id)\n" + " ON UPDATE CASCADE ON DELETE RESTRICT,\n" + " FOREIGN KEY (customer_id)\n" + " REFERENCES `cus``tomer`(id)\n" + ") ENGINE=INNODB;" ); /* Test that I_S implementation is equivalent to parsing "show create table" . Get result sets using either method and compare (ignore minor differences INT vs SMALLINT */ ResultSet rs1 = ((MariaDbDatabaseMetaData) sharedConnection.getMetaData()) .getImportedKeysUsingShowCreateTable("testj", null, "product_order"); ResultSet rs2 = ((MariaDbDatabaseMetaData) sharedConnection.getMetaData()) .getImportedKeysUsingInformationSchema("testj", null, "product_order"); assertEquals(rs1.getMetaData().getColumnCount(), rs2.getMetaData().getColumnCount()); while (rs1.next()) { assertTrue(rs2.next()); for (int i = 1; i <= rs1.getMetaData().getColumnCount(); i++) { Object s1 = rs1.getObject(i); Object s2 = rs2.getObject(i); if (s1 instanceof Number && s2 instanceof Number) { assertEquals(((Number) s1).intValue(), ((Number) s2).intValue()); } else { if (s1 != null && s2 != null && !s1.equals(s2)) { assertTrue(false); } assertEquals(s1, s2); } } } /* Also compare metadata */ ResultSetMetaData md1 = rs1.getMetaData(); ResultSetMetaData md2 = rs2.getMetaData(); for (int i = 1; i <= md1.getColumnCount(); i++) { assertEquals(md1.getColumnLabel(i), md2.getColumnLabel(i)); } st.execute("DROP TABLE IF EXISTS product_order"); st.execute("DROP TABLE IF EXISTS t1.product "); st.execute("DROP TABLE IF EXISTS `cus``tomer`"); st.execute("DROP DATABASE IF EXISTS test1"); } @Test public void exportedKeysTest() throws SQLException { Statement stmt = sharedConnection.createStatement(); stmt.execute("drop table if exists fore_key0"); stmt.execute("drop table if exists fore_key1"); stmt.execute("drop table if exists prim_key"); stmt.execute("create table prim_key (id int not null primary key, " + "val varchar(20)) engine=innodb"); stmt.execute("create table fore_key0 (id int not null primary key, " + "id_ref0 int, foreign key (id_ref0) references prim_key(id)) engine=innodb"); stmt.execute("create table fore_key1 (id int not null primary key, " + "id_ref1 int, foreign key (id_ref1) references prim_key(id) on update cascade) engine=innodb"); DatabaseMetaData dbmd = sharedConnection.getMetaData(); ResultSet rs = dbmd.getExportedKeys("testj", null, "prim_key"); int counter = 0; while (rs.next()) { assertEquals("id", rs.getString("pkcolumn_name")); assertEquals("fore_key" + counter, rs.getString("fktable_name")); assertEquals("id_ref" + counter, rs.getString("fkcolumn_name")); counter++; } assertEquals(2, counter); stmt.execute("drop table if exists fore_key0"); stmt.execute("drop table if exists fore_key1"); stmt.execute("drop table if exists prim_key"); } @Test public void importedKeysTest() throws SQLException { Statement stmt = sharedConnection.createStatement(); stmt.execute("drop table if exists fore_key0"); stmt.execute("drop table if exists fore_key1"); stmt.execute("drop table if exists prim_key"); stmt.execute("create table prim_key (id int not null primary key, " + "val varchar(20)) engine=innodb"); stmt.execute("create table fore_key0 (id int not null primary key, " + "id_ref0 int, foreign key (id_ref0) references prim_key(id)) engine=innodb"); stmt.execute("create table fore_key1 (id int not null primary key, " + "id_ref1 int, foreign key (id_ref1) references prim_key(id) on update cascade) engine=innodb"); DatabaseMetaData dbmd = sharedConnection.getMetaData(); ResultSet rs = dbmd.getImportedKeys(sharedConnection.getCatalog(), null, "fore_key0"); int counter = 0; while (rs.next()) { assertEquals("id", rs.getString("pkcolumn_name")); assertEquals("prim_key", rs.getString("pktable_name")); counter++; } assertEquals(1, counter); stmt.execute("drop table if exists fore_key0"); stmt.execute("drop table if exists fore_key1"); stmt.execute("drop table if exists prim_key"); } @Test public void testGetCatalogs() throws SQLException { DatabaseMetaData dbmd = sharedConnection.getMetaData(); ResultSet rs = dbmd.getCatalogs(); boolean haveMysql = false; boolean haveInformationSchema = false; while (rs.next()) { String cat = rs.getString(1); if (cat.equalsIgnoreCase("mysql")) { haveMysql = true; } else if (cat.equalsIgnoreCase("information_schema")) { haveInformationSchema = true; } } assertTrue(haveMysql); assertTrue(haveInformationSchema); } @Test public void testGetTables() throws SQLException { Statement stmt = sharedConnection.createStatement(); stmt.execute("drop table if exists fore_key0"); stmt.execute("drop table if exists fore_key1"); stmt.execute("drop table if exists prim_key"); stmt.execute("create table prim_key (id int not null primary key, " + "val varchar(20)) engine=innodb"); stmt.execute("create table fore_key0 (id int not null primary key, " + "id_ref0 int, foreign key (id_ref0) references prim_key(id)) engine=innodb"); stmt.execute("create table fore_key1 (id int not null primary key, " + "id_ref1 int, foreign key (id_ref1) references prim_key(id) on update cascade) engine=innodb"); DatabaseMetaData dbmd = sharedConnection.getMetaData(); ResultSet rs = dbmd.getTables(null, null, "prim_key", null); assertEquals(true, rs.next()); rs = dbmd.getTables("", null, "prim_key", null); assertEquals(true, rs.next()); } @Test public void testGetTables2() throws SQLException { DatabaseMetaData dbmd = sharedConnection.getMetaData(); ResultSet rs = dbmd.getTables("information_schema", null, "TABLE_PRIVILEGES", new String[]{"SYSTEM VIEW"}); assertEquals(true, rs.next()); assertEquals(false, rs.next()); rs = dbmd.getTables(null, null, "TABLE_PRIVILEGES", new String[]{"TABLE"}); assertEquals(false, rs.next()); } @Test public void testGetTables3() throws SQLException { Statement stmt = sharedConnection.createStatement(); stmt.execute("drop table if exists table_type_test"); stmt.execute("create table table_type_test (id int not null primary key, " + "val varchar(20)) engine=innodb"); DatabaseMetaData dbmd = sharedConnection.getMetaData(); ResultSet tableSet = dbmd.getTables(null, null, "table_type_test", null); assertEquals(true, tableSet.next()); String tableName = tableSet.getString("TABLE_NAME"); assertEquals("table_type_test", tableName); String tableType = tableSet.getString("TABLE_TYPE"); assertEquals("TABLE", tableType); // see for possible values https://docs.oracle.com/javase/7/docs/api/java/sql/DatabaseMetaData.html#getTableTypes%28%29 } @Test public void testGetColumns() throws SQLException { //mysql 5.6 doesn't permit VIRTUAL keyword Assume.assumeTrue(isMariadbServer() || !isMariadbServer() && minVersion(5, 7)); if (minVersion(10, 2) || !isMariadbServer()) { createTable("tablegetcolumns", "a INT NOT NULL primary key auto_increment, b VARCHAR(32), c INT AS (CHAR_LENGTH(b)) VIRTUAL, " + "d VARCHAR(5) AS (left(b,5)) STORED", "CHARACTER SET 'utf8mb4'"); } else { createTable("tablegetcolumns", "a INT NOT NULL primary key auto_increment, b VARCHAR(32), c INT AS (CHAR_LENGTH(b)) VIRTUAL, " + "d VARCHAR(5) AS (left(b,5)) PERSISTENT", "CHARACTER SET 'utf8mb4'"); } DatabaseMetaData dbmd = sharedConnection.getMetaData(); ResultSet rs = dbmd.getColumns(null, null, "tablegetcolumns", null); assertTrue(rs.next()); assertEquals("testj",rs.getString(1)); //TABLE_CAT assertEquals(null, rs.getString(2)); //TABLE_SCHEM assertEquals("tablegetcolumns", rs.getString(3)); //TABLE_NAME assertEquals("a", rs.getString(4)); //COLUMN_NAME assertEquals(Types.INTEGER, rs.getInt(5)); //DATA_TYPE assertEquals("INT", rs.getString(6)); //"TYPE_NAME assertEquals(10, rs.getInt(7)); //"COLUMN_SIZE assertEquals(0, rs.getInt(9)); //DECIMAL_DIGITS assertEquals(10, rs.getInt(10)); //NUM_PREC_RADIX assertEquals(0, rs.getInt(11)); //NULLABLE assertEquals("", rs.getString(12)); //REMARKS assertEquals(null, rs.getString(13)); //COLUMN_DEF assertEquals(0, rs.getInt(16)); //CHAR_OCTET_LENGTH assertEquals(1, rs.getInt(17)); //ORDINAL_POSITION assertEquals("NO", rs.getString(18)); //IS_NULLABLE assertEquals(null, rs.getString(19)); //SCOPE_CATALOG assertEquals(null, rs.getString(20)); //SCOPE_SCHEMA assertEquals(null, rs.getString(21)); //SCOPE_TABLE assertEquals(0, rs.getShort(22)); //SOURCE_DATA_TYPE assertEquals("YES", rs.getString(23)); //IS_AUTOINCREMENT assertEquals("NO", rs.getString(24)); //IS_GENERATEDCOLUMN assertTrue(rs.next()); assertEquals("testj",rs.getString(1)); //TABLE_CAT assertEquals(null, rs.getString(2)); //TABLE_SCHEM assertEquals("tablegetcolumns", rs.getString(3)); //TABLE_NAME assertEquals("b", rs.getString(4)); //COLUMN_NAME assertEquals(Types.VARCHAR, rs.getInt(5)); //DATA_TYPE assertEquals("VARCHAR", rs.getString(6)); //"TYPE_NAME assertEquals(32, rs.getInt(7)); //"COLUMN_SIZE assertEquals(0, rs.getInt(9)); //DECIMAL_DIGITS assertEquals(10, rs.getInt(10)); //NUM_PREC_RADIX assertEquals(1, rs.getInt(11)); //NULLABLE assertEquals("", rs.getString(12)); //REMARKS assertEquals(null, rs.getString(13)); //COLUMN_DEF assertEquals(32 * 4, rs.getInt(16)); //CHAR_OCTET_LENGTH assertEquals(2, rs.getInt(17)); //ORDINAL_POSITION assertEquals("YES", rs.getString(18)); //IS_NULLABLE assertEquals(null, rs.getString(19)); //SCOPE_CATALOG assertEquals(null, rs.getString(20)); //SCOPE_SCHEMA assertEquals(null, rs.getString(21)); //SCOPE_TABLE assertEquals(0, rs.getShort(22)); //SOURCE_DATA_TYPE assertEquals("NO", rs.getString(23)); //IS_AUTOINCREMENT assertEquals("NO", rs.getString(24)); //IS_GENERATEDCOLUMN assertTrue(rs.next()); assertEquals("testj",rs.getString(1)); //TABLE_CAT assertEquals(null, rs.getString(2)); //TABLE_SCHEM assertEquals("tablegetcolumns", rs.getString(3)); //TABLE_NAME assertEquals("c", rs.getString(4)); //COLUMN_NAME assertEquals(Types.INTEGER, rs.getInt(5)); //DATA_TYPE assertEquals("INT", rs.getString(6)); //"TYPE_NAME assertEquals(10, rs.getInt(7)); //"COLUMN_SIZE assertEquals(0, rs.getInt(9)); //DECIMAL_DIGITS assertEquals(10, rs.getInt(10)); //NUM_PREC_RADIX assertEquals(1, rs.getInt(11)); //NULLABLE assertEquals("", rs.getString(12)); //REMARKS assertEquals(null, rs.getString(13)); //COLUMN_DEF assertEquals(0, rs.getInt(16)); //CHAR_OCTET_LENGTH assertEquals(3, rs.getInt(17)); //ORDINAL_POSITION assertEquals("YES", rs.getString(18)); //IS_NULLABLE assertEquals(null, rs.getString(19)); //SCOPE_CATALOG assertEquals(null, rs.getString(20)); //SCOPE_SCHEMA assertEquals(null, rs.getString(21)); //SCOPE_TABLE assertEquals(0, rs.getShort(22)); //SOURCE_DATA_TYPE assertEquals("NO", rs.getString(23)); //IS_AUTOINCREMENT assertEquals("YES", rs.getString(24)); //IS_GENERATEDCOLUMN assertTrue(rs.next()); assertEquals("testj",rs.getString(1)); //TABLE_CAT assertEquals(null, rs.getString(2)); //TABLE_SCHEM assertEquals("tablegetcolumns", rs.getString(3)); //TABLE_NAME assertEquals("d", rs.getString(4)); //COLUMN_NAME assertEquals(Types.VARCHAR, rs.getInt(5)); //DATA_TYPE assertEquals("VARCHAR", rs.getString(6)); //"TYPE_NAME assertEquals(5, rs.getInt(7)); //"COLUMN_SIZE assertEquals(0, rs.getInt(9)); //DECIMAL_DIGITS assertEquals(10, rs.getInt(10)); //NUM_PREC_RADIX assertEquals(1, rs.getInt(11)); //NULLABLE assertEquals("", rs.getString(12)); //REMARKS assertEquals(null, rs.getString(13)); //COLUMN_DEF assertEquals(5 * 4, rs.getInt(16)); //CHAR_OCTET_LENGTH assertEquals(4, rs.getInt(17)); //ORDINAL_POSITION assertEquals("YES", rs.getString(18)); //IS_NULLABLE assertEquals(null, rs.getString(19)); //SCOPE_CATALOG assertEquals(null, rs.getString(20)); //SCOPE_SCHEMA assertEquals(null, rs.getString(21)); //SCOPE_TABLE assertEquals(0, rs.getShort(22)); //SOURCE_DATA_TYPE assertEquals("NO", rs.getString(23)); //IS_AUTOINCREMENT assertEquals("YES", rs.getString(24)); //IS_GENERATEDCOLUMN assertFalse(rs.next()); } void testResultSetColumns(ResultSet rs, String spec) throws SQLException { ResultSetMetaData rsmd = rs.getMetaData(); String[] tokens = spec.split(","); for (int i = 0; i < tokens.length; i++) { String[] splitTokens = tokens[i].trim().split(" "); String label = splitTokens[0]; String type = splitTokens[1]; int col = i + 1; assertEquals(label, rsmd.getColumnLabel(col)); int columnType = rsmd.getColumnType(col); switch (type) { case "String": assertTrue("invalid type " + columnType + " for " + rsmd.getColumnLabel(col) + ",expected String", columnType == Types.VARCHAR || columnType == Types.NULL || columnType == Types.LONGVARCHAR); break; case "decimal": assertTrue("invalid type " + columnType + "( " + rsmd.getColumnTypeName(col) + " ) for " + rsmd.getColumnLabel(col) + ",expected decimal", columnType == Types.DECIMAL); break; case "int": case "short": assertTrue("invalid type " + columnType + "( " + rsmd.getColumnTypeName(col) + " ) for " + rsmd.getColumnLabel(col) + ",expected numeric", columnType == Types.BIGINT || columnType == Types.INTEGER || columnType == Types.SMALLINT || columnType == Types.TINYINT); break; case "boolean": assertTrue("invalid type " + columnType + "( " + rsmd.getColumnTypeName(col) + " ) for " + rsmd.getColumnLabel(col) + ",expected boolean", columnType == Types.BOOLEAN || columnType == Types.BIT); break; case "null": assertTrue("invalid type " + columnType + " for " + rsmd.getColumnLabel(col) + ",expected null", columnType == Types.NULL); break; default: assertTrue("invalid type '" + type + "'", false); break; } } } @Test public void getAttributesBasic() throws Exception { testResultSetColumns( sharedConnection.getMetaData().getAttributes(null, null, null, null), "TYPE_CAT String,TYPE_SCHEM String,TYPE_NAME String," + "ATTR_NAME String,DATA_TYPE int,ATTR_TYPE_NAME String,ATTR_SIZE int,DECIMAL_DIGITS int," + "NUM_PREC_RADIX int,NULLABLE int,REMARKS String,ATTR_DEF String,SQL_DATA_TYPE int," + "SQL_DATETIME_SUB int, CHAR_OCTET_LENGTH int,ORDINAL_POSITION int,IS_NULLABLE String," + "SCOPE_CATALOG String,SCOPE_SCHEMA String," + "SCOPE_TABLE String,SOURCE_DATA_TYPE short"); } @Test public void identifierCaseSensitivity() throws Exception { if (sharedConnection.getMetaData().supportsMixedCaseIdentifiers()) { /* Case-sensitive identifier handling, we can create both t1 and T1 */ createTable("aB", "i int"); createTable("AB", "i int"); /* Check there is an entry for both T1 and t1 in getTables */ ResultSet rs = sharedConnection.getMetaData().getTables(null, null, "aB", null); assertTrue(rs.next()); assertFalse(rs.next()); rs = sharedConnection.getMetaData().getTables(null, null, "AB", null); assertTrue(rs.next()); assertFalse(rs.next()); } if (sharedConnection.getMetaData().storesMixedCaseIdentifiers()) { /* Case-insensitive, case-preserving */ createTable("aB", "i int"); try { createTable("AB", "i int"); fail("should not get there, since names are case-insensitive"); } catch (SQLException e) { //normal error } /* Check that table is stored case-preserving */ ResultSet rs = sharedConnection.getMetaData().getTables(null, null, "aB%", null); while (rs.next()) { String tableName = rs.getString("TABLE_NAME"); if (tableName.length() == 2) { assertEquals("aB", tableName); } } rs = sharedConnection.getMetaData().getTables(null, null, "AB", null); assertTrue(rs.next()); assertFalse(rs.next()); } if (sharedConnection.getMetaData().storesLowerCaseIdentifiers()) { /* case-insensitive, identifiers converted to lowercase */ /* Case-insensitive, case-preserving */ createTable("aB", "i int"); try { sharedConnection.createStatement().execute("create table AB(i int)"); fail("should not get there, since names are case-insensitive"); } catch (SQLException e) { //normal error } /* Check that table is stored lowercase */ ResultSet rs = sharedConnection.getMetaData().getTables(null, null, "aB%", null); while (rs.next()) { String tableName = rs.getString("TABLE_NAME"); if (tableName.length() == 2) { assertEquals("ab", tableName); } } rs = sharedConnection.getMetaData().getTables(null, null, "AB", null); assertTrue(rs.next()); assertFalse(rs.next()); } assertFalse(sharedConnection.getMetaData().storesUpperCaseIdentifiers()); } @Test public void getBestRowIdentifierBasic() throws SQLException { testResultSetColumns( sharedConnection.getMetaData().getBestRowIdentifier(null, null, "", 0, true), "SCOPE short,COLUMN_NAME String,DATA_TYPE int, TYPE_NAME String," + "COLUMN_SIZE int,BUFFER_LENGTH int," + "DECIMAL_DIGITS short,PSEUDO_COLUMN short"); } @Test public void getClientInfoPropertiesBasic() throws Exception { testResultSetColumns( sharedConnection.getMetaData().getClientInfoProperties(), "NAME String, MAX_LEN int, DEFAULT_VALUE String, DESCRIPTION String"); ResultSet rs = sharedConnection.getMetaData().getClientInfoProperties(); assertTrue(rs.next()); assertEquals("ApplicationName", rs.getString(1)); assertEquals(0x00ffffff, rs.getInt(2)); assertEquals("", rs.getString(3)); assertEquals("The name of the application currently utilizing the connection", rs.getString(4)); assertTrue(rs.next()); assertEquals("ClientUser", rs.getString(1)); assertEquals(0x00ffffff, rs.getInt(2)); assertEquals("", rs.getString(3)); assertEquals("The name of the user that the application using the connection is performing work for. " + "This may not be the same as the user name that was used in establishing the connection.", rs.getString(4)); assertTrue(rs.next()); assertEquals("ClientHostname", rs.getString(1)); assertEquals(0x00ffffff, rs.getInt(2)); assertEquals("", rs.getString(3)); assertEquals("The hostname of the computer the application using the connection is running on", rs.getString(4)); assertFalse(rs.next()); } @Test public void getCatalogsBasic() throws SQLException { testResultSetColumns( sharedConnection.getMetaData().getCatalogs(), "TABLE_CAT String"); } @Test public void getColumnsBasic() throws SQLException { cancelForVersion(10, 1); //due to server error MDEV-8984 if (sharedConnection.getMetaData().getDatabaseProductVersion().startsWith("10.2")) { testResultSetColumns(sharedConnection.getMetaData().getColumns(null, null, null, null), "TABLE_CAT String,TABLE_SCHEM String,TABLE_NAME String,COLUMN_NAME String," + "DATA_TYPE int,TYPE_NAME String,COLUMN_SIZE decimal,BUFFER_LENGTH int," + "DECIMAL_DIGITS int,NUM_PREC_RADIX int,NULLABLE int," + "REMARKS String,COLUMN_DEF String,SQL_DATA_TYPE int," + "SQL_DATETIME_SUB int, CHAR_OCTET_LENGTH decimal," + "ORDINAL_POSITION int,IS_NULLABLE String," + "SCOPE_CATALOG String,SCOPE_SCHEMA String," + "SCOPE_TABLE String,SOURCE_DATA_TYPE null"); } else { testResultSetColumns(sharedConnection.getMetaData().getColumns(null, null, null, null), "TABLE_CAT String,TABLE_SCHEM String,TABLE_NAME String,COLUMN_NAME String," + "DATA_TYPE int,TYPE_NAME String,COLUMN_SIZE int,BUFFER_LENGTH int," + "DECIMAL_DIGITS int,NUM_PREC_RADIX int,NULLABLE int," + "REMARKS String,COLUMN_DEF String,SQL_DATA_TYPE int," + "SQL_DATETIME_SUB int, CHAR_OCTET_LENGTH int," + "ORDINAL_POSITION int,IS_NULLABLE String," + "SCOPE_CATALOG String,SCOPE_SCHEMA String," + "SCOPE_TABLE String,SOURCE_DATA_TYPE null"); } } @Test public void getProcedureColumnsBasic() throws SQLException { testResultSetColumns(sharedConnection.getMetaData().getProcedureColumns(null, null, null, null), "PROCEDURE_CAT String,PROCEDURE_SCHEM String,PROCEDURE_NAME String,COLUMN_NAME String ," + "COLUMN_TYPE short,DATA_TYPE int,TYPE_NAME String,PRECISION int,LENGTH int,SCALE short," + "RADIX short,NULLABLE short,REMARKS String,COLUMN_DEF String,SQL_DATA_TYPE int," + "SQL_DATETIME_SUB int ,CHAR_OCTET_LENGTH int," + "ORDINAL_POSITION int,IS_NULLABLE String,SPECIFIC_NAME String"); } @Test public void getFunctionColumnsBasic() throws SQLException { testResultSetColumns(sharedConnection.getMetaData().getFunctionColumns(null, null, null, null), "FUNCTION_CAT String,FUNCTION_SCHEM String,FUNCTION_NAME String,COLUMN_NAME String,COLUMN_TYPE short," + "DATA_TYPE int,TYPE_NAME String,PRECISION int,LENGTH int,SCALE short,RADIX short," + "NULLABLE short,REMARKS String,CHAR_OCTET_LENGTH int,ORDINAL_POSITION int," + "IS_NULLABLE String,SPECIFIC_NAME String"); } @Test public void getColumnPrivilegesBasic() throws SQLException { testResultSetColumns( sharedConnection.getMetaData().getColumnPrivileges(null, null, "", null), "TABLE_CAT String,TABLE_SCHEM String,TABLE_NAME String,COLUMN_NAME String," + "GRANTOR String,GRANTEE String,PRIVILEGE String,IS_GRANTABLE String"); } @Test public void getTablePrivilegesBasic() throws SQLException { testResultSetColumns( sharedConnection.getMetaData().getTablePrivileges(null, null, null), "TABLE_CAT String,TABLE_SCHEM String,TABLE_NAME String,GRANTOR String," + "GRANTEE String,PRIVILEGE String,IS_GRANTABLE String"); } @Test public void getVersionColumnsBasic() throws SQLException { testResultSetColumns( sharedConnection.getMetaData().getVersionColumns(null, null, null), "SCOPE short, COLUMN_NAME String,DATA_TYPE int,TYPE_NAME String," + "COLUMN_SIZE int,BUFFER_LENGTH int,DECIMAL_DIGITS short," + "PSEUDO_COLUMN short"); } @Test public void getPrimaryKeysBasic() throws SQLException { testResultSetColumns( sharedConnection.getMetaData().getPrimaryKeys(null, null, null), "TABLE_CAT String,TABLE_SCHEM String,TABLE_NAME String,COLUMN_NAME String,KEY_SEQ short,PK_NAME String" ); } @Test public void getImportedKeysBasic() throws SQLException { testResultSetColumns( sharedConnection.getMetaData().getImportedKeys(null, null, ""), "PKTABLE_CAT String,PKTABLE_SCHEM String,PKTABLE_NAME String, PKCOLUMN_NAME String,FKTABLE_CAT String," + "FKTABLE_SCHEM String,FKTABLE_NAME String,FKCOLUMN_NAME String,KEY_SEQ short," + "UPDATE_RULE short,DELETE_RULE short,FK_NAME String,PK_NAME String,DEFERRABILITY short"); } @Test public void getExportedKeysBasic() throws SQLException { testResultSetColumns( sharedConnection.getMetaData().getExportedKeys(null, null, ""), "PKTABLE_CAT String,PKTABLE_SCHEM String,PKTABLE_NAME String, PKCOLUMN_NAME String,FKTABLE_CAT String," + "FKTABLE_SCHEM String,FKTABLE_NAME String,FKCOLUMN_NAME String,KEY_SEQ short," + "UPDATE_RULE short, DELETE_RULE short,FK_NAME String,PK_NAME String,DEFERRABILITY short"); } @Test public void getCrossReferenceBasic() throws SQLException { testResultSetColumns( sharedConnection.getMetaData().getCrossReference(null, null, "", null, null, ""), "PKTABLE_CAT String,PKTABLE_SCHEM String,PKTABLE_NAME String, PKCOLUMN_NAME String,FKTABLE_CAT String," + "FKTABLE_SCHEM String,FKTABLE_NAME String,FKCOLUMN_NAME String,KEY_SEQ short," + "UPDATE_RULE short,DELETE_RULE short,FK_NAME String,PK_NAME String,DEFERRABILITY short"); } @Test public void getUdtsBasic() throws SQLException { testResultSetColumns( sharedConnection.getMetaData().getUDTs(null, null, null, null), "TYPE_CAT String,TYPE_SCHEM String,TYPE_NAME String,CLASS_NAME String,DATA_TYPE int," + "REMARKS String,BASE_TYPE short"); } @Test public void getSuperTypesBasic() throws SQLException { testResultSetColumns( sharedConnection.getMetaData().getSuperTypes(null, null, null), "TYPE_CAT String,TYPE_SCHEM String,TYPE_NAME String,SUPERTYPE_CAT String," + "SUPERTYPE_SCHEM String,SUPERTYPE_NAME String"); } @Test public void getFunctionsBasic() throws SQLException { testResultSetColumns( sharedConnection.getMetaData().getFunctions(null, null, null), "FUNCTION_CAT String, FUNCTION_SCHEM String,FUNCTION_NAME String,REMARKS String,FUNCTION_TYPE short, " + "SPECIFIC_NAME String"); } @Test public void getSuperTablesBasic() throws SQLException { testResultSetColumns( sharedConnection.getMetaData().getSuperTables(null, null, null), "TABLE_CAT String,TABLE_SCHEM String,TABLE_NAME String, SUPERTABLE_NAME String"); } @Test public void testGetSchemas2() throws SQLException { DatabaseMetaData dbmd = sharedConnection.getMetaData(); ResultSet rs = dbmd.getCatalogs(); boolean foundTestUnitsJdbc = false; while (rs.next()) { if (rs.getString(1).equals("testj")) { foundTestUnitsJdbc = true; } } assertEquals(true, foundTestUnitsJdbc); } /* Verify default behavior for nullCatalogMeansCurrent (=true) */ @Test public void nullCatalogMeansCurrent() throws Exception { String catalog = sharedConnection.getCatalog(); ResultSet rs = sharedConnection.getMetaData().getColumns(null, null, null, null); while (rs.next()) { assertTrue(rs.getString("TABLE_CAT").equalsIgnoreCase(catalog)); } } /* Verify that "nullCatalogMeansCurrent=false" works (i.e information_schema columns are returned)*/ @Test public void nullCatalogMeansCurrent2() throws Exception { try (Connection connection = setConnection("&nullCatalogMeansCurrent=false")) { boolean haveInformationSchema = false; ResultSet rs = connection.getMetaData().getColumns(null, null, null, null); while (rs.next()) { if (rs.getString("TABLE_CAT").equalsIgnoreCase("information_schema")) { haveInformationSchema = true; break; } } assertTrue(haveInformationSchema); } } @Test public void testGetTypeInfoBasic() throws SQLException { testResultSetColumns( sharedConnection.getMetaData().getTypeInfo(), "TYPE_NAME String,DATA_TYPE int,PRECISION int,LITERAL_PREFIX String," + "LITERAL_SUFFIX String,CREATE_PARAMS String, NULLABLE short,CASE_SENSITIVE boolean," + "SEARCHABLE short,UNSIGNED_ATTRIBUTE boolean,FIXED_PREC_SCALE boolean, " + "AUTO_INCREMENT boolean, LOCAL_TYPE_NAME String,MINIMUM_SCALE short,MAXIMUM_SCALE short," + "SQL_DATA_TYPE int,SQL_DATETIME_SUB int, NUM_PREC_RADIX int"); } @Test public void getColumnsTest() throws SQLException { DatabaseMetaData dmd = sharedConnection.getMetaData(); ResultSet rs = dmd.getColumns(sharedConnection.getCatalog(), null, "manycols", null); while (rs.next()) { String columnName = rs.getString("column_name"); int type = rs.getInt("data_type"); String typeName = rs.getString("type_name"); assertTrue(typeName.indexOf("(") == -1); for (char c : typeName.toCharArray()) { assertTrue("bad typename " + typeName, c == ' ' || Character.isUpperCase(c)); } checkType(columnName, type, "tiny", Types.TINYINT); checkType(columnName, type, "tiny_uns", Types.TINYINT); checkType(columnName, type, "small", Types.SMALLINT); checkType(columnName, type, "small_uns", Types.SMALLINT); checkType(columnName, type, "medium", Types.INTEGER); checkType(columnName, type, "medium_uns", Types.INTEGER); checkType(columnName, type, "int_col", Types.INTEGER); checkType(columnName, type, "int_col_uns", Types.INTEGER); checkType(columnName, type, "big", Types.BIGINT); checkType(columnName, type, "big_uns", Types.BIGINT); checkType(columnName, type, "decimal_col", Types.DECIMAL); checkType(columnName, type, "fcol", Types.REAL); checkType(columnName, type, "fcol_uns", Types.REAL); checkType(columnName, type, "dcol", Types.DOUBLE); checkType(columnName, type, "dcol_uns", Types.DOUBLE); checkType(columnName, type, "date_col", Types.DATE); checkType(columnName, type, "time_col", Types.TIME); checkType(columnName, type, "timestamp_col", Types.TIMESTAMP); checkType(columnName, type, "year_col", Types.DATE); checkType(columnName, type, "bit_col", Types.BIT); checkType(columnName, type, "char_col", Types.CHAR); checkType(columnName, type, "varchar_col", Types.VARCHAR); checkType(columnName, type, "binary_col", Types.BINARY); checkType(columnName, type, "tinyblob_col", Types.VARBINARY); checkType(columnName, type, "blob_col", Types.LONGVARBINARY); checkType(columnName, type, "longblob_col", Types.LONGVARBINARY); checkType(columnName, type, "mediumblob_col", Types.LONGVARBINARY); checkType(columnName, type, "tinytext_col", Types.VARCHAR); checkType(columnName, type, "text_col", Types.LONGVARCHAR); checkType(columnName, type, "mediumtext_col", Types.LONGVARCHAR); checkType(columnName, type, "longtext_col", Types.LONGVARCHAR); } } @Test public void yearIsShortType() throws Exception { try (Connection connection = setConnection("&yearIsDateType=false")) { connection.createStatement().execute("insert into ytab values(72)"); try (ResultSet rs = connection.getMetaData().getColumns(connection.getCatalog(), null, "ytab", null)) { assertTrue(rs.next()); assertEquals(rs.getInt("DATA_TYPE"), Types.SMALLINT); } try (ResultSet rs1 = connection.createStatement().executeQuery("select * from ytab")) { assertEquals(rs1.getMetaData().getColumnType(1), Types.SMALLINT); assertTrue(rs1.next()); assertTrue(rs1.getObject(1) instanceof Short); assertEquals(rs1.getShort(1), 1972); } } } /* CONJ-15 */ @Test public void maxCharLengthUtf8() throws Exception { DatabaseMetaData dmd = sharedConnection.getMetaData(); ResultSet rs = dmd.getColumns(sharedConnection.getCatalog(), null, "maxcharlength", null); assertTrue(rs.next()); assertEquals(rs.getInt("COLUMN_SIZE"), 1); } @Test public void conj72() throws Exception { try (Connection connection = setConnection("&tinyInt1isBit=true")) { connection.createStatement().execute("insert into conj72 values(1)"); ResultSet rs = connection.getMetaData().getColumns(connection.getCatalog(), null, "conj72", null); assertTrue(rs.next()); assertEquals(rs.getInt("DATA_TYPE"), Types.BIT); ResultSet rs1 = connection.createStatement().executeQuery("select * from conj72"); assertEquals(rs1.getMetaData().getColumnType(1), Types.BIT); } } @Test public void getPrecision() throws SQLException { createTable("getPrecision", "num1 NUMERIC(9,4), " + "num2 NUMERIC (9,0)," + "num3 NUMERIC (9,4) UNSIGNED," + "num4 NUMERIC (9,0) UNSIGNED," + "num5 FLOAT(9,4)," + "num6 FLOAT(9,4) UNSIGNED," + "num7 DOUBLE(9,4)," + "num8 DOUBLE(9,4) UNSIGNED" ); Statement stmt = sharedConnection.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM getPrecision"); ResultSetMetaData rsmd = rs.getMetaData(); assertEquals(9, rsmd.getPrecision(1)); assertEquals(4, rsmd.getScale(1)); assertEquals(9, rsmd.getPrecision(2)); assertEquals(0, rsmd.getScale(2)); assertEquals(9, rsmd.getPrecision(3)); assertEquals(4, rsmd.getScale(3)); assertEquals(9, rsmd.getPrecision(4)); assertEquals(0, rsmd.getScale(4)); assertEquals(9, rsmd.getPrecision(5)); assertEquals(4, rsmd.getScale(5)); assertEquals(9, rsmd.getPrecision(6)); assertEquals(4, rsmd.getScale(6)); assertEquals(9, rsmd.getPrecision(7)); assertEquals(4, rsmd.getScale(7)); assertEquals(9, rsmd.getPrecision(8)); assertEquals(4, rsmd.getScale(8)); } @Test public void getTimePrecision() throws SQLException { Assume.assumeTrue(doPrecisionTest); createTable("getTimePrecision", "d date, " + "t1 datetime(0)," + "t2 datetime(6)," + "t3 timestamp(0) DEFAULT '2000-01-01 00:00:00'," + "t4 timestamp(6) DEFAULT '2000-01-01 00:00:00'," + "t5 time(0)," + "t6 time(6)" ); Statement stmt = sharedConnection.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM getTimePrecision"); ResultSetMetaData rsmd = rs.getMetaData(); //date assertEquals(10, rsmd.getPrecision(1)); assertEquals(0, rsmd.getScale(1)); //datetime(0) assertEquals(19, rsmd.getPrecision(2)); assertEquals(0, rsmd.getScale(2)); //datetime(6) assertEquals(26, rsmd.getPrecision(3)); assertEquals(6, rsmd.getScale(3)); //timestamp(0) assertEquals(19, rsmd.getPrecision(4)); assertEquals(0, rsmd.getScale(4)); //timestamp(6) assertEquals(26, rsmd.getPrecision(5)); assertEquals(6, rsmd.getScale(5)); //time(0) assertEquals(10, rsmd.getPrecision(6)); assertEquals(0, rsmd.getScale(6)); //time(6) assertEquals(17, rsmd.getPrecision(7)); assertEquals(6, rsmd.getScale(7)); } @Test public void metaTimeResultSet() throws SQLException { Assume.assumeTrue(doPrecisionTest); createTable("getTimePrecision", "d date, " + "t1 datetime(0)," + "t2 datetime(6)," + "t3 timestamp(0) DEFAULT '2000-01-01 00:00:00'," + "t4 timestamp(6) DEFAULT '2000-01-01 00:00:00'," + "t5 time(0)," + "t6 time(6)"); final int columnSizeField = 7; DatabaseMetaData dmd = sharedConnection.getMetaData(); ResultSet rs = dmd.getColumns(null, null, "getTimePrecision", null); //date assertTrue(rs.next()); assertEquals(10, rs.getInt(columnSizeField)); //datetime(0) assertTrue(rs.next()); assertEquals(19, rs.getInt(columnSizeField)); //datetime(6) assertTrue(rs.next()); assertEquals(26, rs.getInt(columnSizeField)); //timestamp(0) assertTrue(rs.next()); assertEquals(19, rs.getInt(columnSizeField)); //timestamp(6) assertTrue(rs.next()); assertEquals(26, rs.getInt(columnSizeField)); //time(0) assertTrue(rs.next()); assertEquals(10, rs.getInt(columnSizeField)); //time(6) assertTrue(rs.next()); assertEquals(17, rs.getInt(columnSizeField)); assertFalse(rs.next()); } /** * CONJ-401 - getProcedureColumns precision when server doesn't support precision. * * @throws SQLException if connection error occur */ @Test public void metaTimeNoPrecisionProcedureResultSet() throws SQLException { createProcedure("getProcTimePrecision2", "(IN I date, " + "IN t1 DATETIME," + "IN t3 timestamp," + "IN t5 time) BEGIN SELECT I; END"); final int precisionField = 8; final int lengthField = 9; final int scaleField = 10; DatabaseMetaData dmd = sharedConnection.getMetaData(); ResultSet rs = dmd.getProcedureColumns(null, null, "getProcTimePrecision2", null); //date assertTrue(rs.next()); assertEquals(10, rs.getInt(precisionField)); assertEquals(10, rs.getInt(lengthField)); assertEquals(0, rs.getInt(scaleField)); assertTrue(rs.wasNull()); //datetime(0) assertTrue(rs.next()); assertEquals(19, rs.getInt(precisionField)); assertEquals(19, rs.getInt(lengthField)); assertEquals(0, rs.getInt(scaleField)); //timestamp(0) assertTrue(rs.next()); assertEquals(19, rs.getInt(precisionField)); assertEquals(19, rs.getInt(lengthField)); assertEquals(0, rs.getInt(scaleField)); //time(0) assertTrue(rs.next()); assertEquals(10, rs.getInt(precisionField)); assertEquals(10, rs.getInt(lengthField)); assertEquals(0, rs.getInt(scaleField)); assertFalse(rs.next()); } /** * CONJ-381 - getProcedureColumns returns NULL as TIMESTAMP/DATETIME precision instead of 19. * * @throws SQLException if connection error occur */ @Test public void metaTimeProcedureResultSet() throws SQLException { Assume.assumeTrue(doPrecisionTest); createProcedure("getProcTimePrecision", "(IN I date, " + "IN t1 DATETIME(0)," + "IN t2 DATETIME(6)," + "IN t3 timestamp(0)," + "IN t4 timestamp(6)," + "IN t5 time ," + "IN t6 time(6)) BEGIN SELECT I; END"); final int precisionField = 8; final int lengthField = 9; final int scaleField = 10; DatabaseMetaData dmd = sharedConnection.getMetaData(); ResultSet rs = dmd.getProcedureColumns(null, null, "getProcTimePrecision", null); //date assertTrue(rs.next()); assertEquals(10, rs.getInt(precisionField)); assertEquals(10, rs.getInt(lengthField)); assertEquals(0, rs.getInt(scaleField)); assertTrue(rs.wasNull()); //datetime(0) assertTrue(rs.next()); assertEquals(19, rs.getInt(precisionField)); assertEquals(19, rs.getInt(lengthField)); assertEquals(0, rs.getInt(scaleField)); //datetime(6) assertTrue(rs.next()); assertEquals(26, rs.getInt(precisionField)); assertEquals(26, rs.getInt(lengthField)); assertEquals(6, rs.getInt(scaleField)); //timestamp(0) assertTrue(rs.next()); assertEquals(19, rs.getInt(precisionField)); assertEquals(19, rs.getInt(lengthField)); assertEquals(0, rs.getInt(scaleField)); //timestamp(6) assertTrue(rs.next()); assertEquals(26, rs.getInt(precisionField)); assertEquals(26, rs.getInt(lengthField)); assertEquals(6, rs.getInt(scaleField)); //time(0) assertTrue(rs.next()); assertEquals(10, rs.getInt(precisionField)); assertEquals(10, rs.getInt(lengthField)); assertEquals(0, rs.getInt(scaleField)); //time(6) assertTrue(rs.next()); assertEquals(17, rs.getInt(precisionField)); assertEquals(17, rs.getInt(lengthField)); assertEquals(6, rs.getInt(scaleField)); assertFalse(rs.next()); } }