diff --git a/CHANGES b/CHANGES index c3bd480da..c74a46588 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,8 @@ Version 8.0.27 + - Fix for Bug#104641 (33237255), DatabaseMetaData.getImportedKeys can return duplicated foreign keys. + - Fix for Bug#33185116, Have method ResultSet.getBoolean() supporting conversion of 'T' and 'F' in a VARCHAR to True/False (boolean). - Fix for Bug#31117686, PROTOCOL ALLOWLIST NOT COMPATIBLE WITH IBM JAVA. diff --git a/src/main/user-impl/java/com/mysql/cj/jdbc/DatabaseMetaDataUsingInfoSchema.java b/src/main/user-impl/java/com/mysql/cj/jdbc/DatabaseMetaDataUsingInfoSchema.java index 285c3f8fe..8f1d3e19f 100644 --- a/src/main/user-impl/java/com/mysql/cj/jdbc/DatabaseMetaDataUsingInfoSchema.java +++ b/src/main/user-impl/java/com/mysql/cj/jdbc/DatabaseMetaDataUsingInfoSchema.java @@ -453,14 +453,11 @@ public java.sql.ResultSet getImportedKeys(String catalog, String schema, String sqlBuf.append(generateUpdateRuleClause()); sqlBuf.append(" AS UPDATE_RULE,"); sqlBuf.append(generateDeleteRuleClause()); - sqlBuf.append(" AS DELETE_RULE, A.CONSTRAINT_NAME AS FK_NAME, TC.CONSTRAINT_NAME AS PK_NAME,"); + sqlBuf.append(" AS DELETE_RULE, A.CONSTRAINT_NAME AS FK_NAME, R.UNIQUE_CONSTRAINT_NAME AS PK_NAME,"); sqlBuf.append(importedKeyNotDeferrable); sqlBuf.append(" AS DEFERRABILITY FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE A"); sqlBuf.append(" JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS B USING (CONSTRAINT_NAME, TABLE_NAME) "); sqlBuf.append(generateOptionalRefContraintsJoin()); - sqlBuf.append(" LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC ON (A.REFERENCED_TABLE_SCHEMA = TC.TABLE_SCHEMA"); - sqlBuf.append(" AND A.REFERENCED_TABLE_NAME = TC.TABLE_NAME"); - sqlBuf.append(" AND TC.CONSTRAINT_TYPE IN ('UNIQUE', 'PRIMARY KEY'))"); sqlBuf.append("WHERE B.CONSTRAINT_TYPE = 'FOREIGN KEY'"); if (db != null) { sqlBuf.append(" AND A.TABLE_SCHEMA = ?"); diff --git a/src/test/java/testsuite/regression/MetaDataRegressionTest.java b/src/test/java/testsuite/regression/MetaDataRegressionTest.java index d3a84e79c..cd91af894 100644 --- a/src/test/java/testsuite/regression/MetaDataRegressionTest.java +++ b/src/test/java/testsuite/regression/MetaDataRegressionTest.java @@ -5314,4 +5314,81 @@ public void testBug95280() throws Exception { } } } + + /** + * Tests fix for Bug#104641 (33237255), DatabaseMetaData.getImportedKeys can return duplicated foreign keys. + * + * @throws Exception + */ + @Test + public void testBug104641() throws Exception { + String databaseName1 = "dbBug104641"; + createDatabase(databaseName1); + createTable(databaseName1 + ".table1", + "(`CREATED` datetime DEFAULT NULL,`ID` bigint NOT NULL AUTO_INCREMENT,`LRN_ID` bigint DEFAULT '0',`USERNAME` varchar(50) NOT NULL," + + "PRIMARY KEY (`ID`),UNIQUE KEY `U_table1_LRN_ID` (`LRN_ID`),UNIQUE KEY `U_table1_USERNAME` (`USERNAME`) )"); + createTable(databaseName1 + ".table2", + "(`AL_ID` varchar(50) DEFAULT NULL,`CREATED` datetime DEFAULT NULL,`ID` bigint NOT NULL AUTO_INCREMENT,`USER_ID` bigint DEFAULT NULL," + + "PRIMARY KEY (`ID`),KEY `fk_table2_user_id` (`USER_ID`),KEY `index_al_id1` (`AL_ID`)," + + "CONSTRAINT `fk_table2_user_id` FOREIGN KEY (`USER_ID`) REFERENCES `table1` (`ID`) )"); + createTable(databaseName1 + ".table3", + "(`AL_ID` varchar(50) DEFAULT NULL,`ID` bigint NOT NULL AUTO_INCREMENT,`USER_ID` bigint DEFAULT NULL,`LRN_ID` bigint DEFAULT '0'," + + "PRIMARY KEY (`ID`),KEY `fk_table3_LRN_ID` (`LRN_ID`),KEY `index_al_id2` (`AL_ID`)," + + "CONSTRAINT `fk_table3_LRN_ID` FOREIGN KEY `U_table1_LRN_ID` (`LRN_ID`) REFERENCES `table1` (`LRN_ID`) )"); + + Properties props = new Properties(); + props.setProperty(PropertyKey.useSSL.getKeyName(), "false"); + props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true"); + for (boolean useIS : new boolean[] { false, true }) { + for (String databaseTerm : new String[] { "CATALOG", "SCHEMA" }) { + props.setProperty(PropertyKey.useInformationSchema.getKeyName(), "" + useIS); + props.setProperty(PropertyKey.databaseTerm.getKeyName(), databaseTerm); + + boolean dbTermIsSchema = databaseTerm.contentEquals("SCHEMA"); + + String err = "useInformationSchema=" + useIS + ", databaseTerm=" + databaseTerm; + Connection con = getConnectionWithProps(props); + DatabaseMetaData meta = con.getMetaData(); + + this.rs = dbTermIsSchema ? meta.getImportedKeys(null, databaseName1, "table2") : meta.getImportedKeys(databaseName1, null, "table2"); + assertTrue(this.rs.next(), err); + assertEquals(dbTermIsSchema ? "def" : databaseName1, this.rs.getString("PKTABLE_CAT"), err); + assertEquals(dbTermIsSchema ? databaseName1 : null, this.rs.getString("PKTABLE_SCHEM"), err); + assertEquals(dbTermIsSchema ? "def" : databaseName1, this.rs.getString("FKTABLE_CAT"), err); + assertEquals(dbTermIsSchema ? databaseName1 : null, this.rs.getString("FKTABLE_SCHEM"), err); + assertEquals("table1", this.rs.getString("PKTABLE_NAME"), err); + assertEquals("ID", this.rs.getString("PKCOLUMN_NAME"), err); + assertEquals("table2", this.rs.getString("FKTABLE_NAME"), err); + assertEquals("USER_ID", this.rs.getString("FKCOLUMN_NAME"), err); + assertEquals(1, this.rs.getInt("KEY_SEQ"), err); + assertEquals(1, this.rs.getInt("UPDATE_RULE"), err); + assertEquals(1, this.rs.getInt("DELETE_RULE"), err); + assertEquals("fk_table2_user_id", this.rs.getString("FK_NAME"), err); + assertEquals(useIS ? "PRIMARY" : null, this.rs.getString("PK_NAME"), err); + assertEquals(7, this.rs.getInt("DEFERRABILITY"), err); + assertFalse(this.rs.next(), err); + + this.rs = dbTermIsSchema ? meta.getImportedKeys(null, databaseName1, "table3") : meta.getImportedKeys(databaseName1, null, "table3"); + assertTrue(this.rs.next(), err); + assertEquals(dbTermIsSchema ? "def" : databaseName1, this.rs.getString("PKTABLE_CAT"), err); + assertEquals(dbTermIsSchema ? databaseName1 : null, this.rs.getString("PKTABLE_SCHEM"), err); + assertEquals(dbTermIsSchema ? "def" : databaseName1, this.rs.getString("FKTABLE_CAT"), err); + assertEquals(dbTermIsSchema ? databaseName1 : null, this.rs.getString("FKTABLE_SCHEM"), err); + assertEquals("table1", this.rs.getString("PKTABLE_NAME"), err); + assertEquals("LRN_ID", this.rs.getString("PKCOLUMN_NAME"), err); + assertEquals("table3", this.rs.getString("FKTABLE_NAME"), err); + assertEquals("LRN_ID", this.rs.getString("FKCOLUMN_NAME"), err); + assertEquals(1, this.rs.getInt("KEY_SEQ"), err); + assertEquals(1, this.rs.getInt("UPDATE_RULE"), err); + assertEquals(1, this.rs.getInt("DELETE_RULE"), err); + assertEquals("fk_table3_LRN_ID", this.rs.getString("FK_NAME"), err); + assertEquals(useIS ? "U_table1_LRN_ID" : null, this.rs.getString("PK_NAME"), err); + assertEquals(7, this.rs.getInt("DEFERRABILITY"), err); + assertFalse(this.rs.next(), err); + + con.close(); + } + } + + } }