in exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/v1/jdbc/statements/jdbc/JdbcDatabaseMetadataImpl.kt [433:483]
override fun tableConstraints(tables: List<Table>): Map<String, List<ForeignKeyConstraint>> {
val allTables = SchemaUtils.sortTablesByReferences(tables).associateBy { it.nameInDatabaseCaseUnquoted() }
val dialect = currentDialect
return if (dialect is MysqlDialect) {
val inTableList = allTables.keys.joinToString("','", prefix = " ku.TABLE_NAME IN ('", postfix = "')")
val tableSchema = "'${tables.mapNotNull { it.schemaName }.toSet().singleOrNull() ?: currentSchema}'"
val constraintsToLoad = HashMap<String, MutableMap<String, ForeignKeyConstraint>>()
metadata.connection.executeSQL(
"""
SELECT
rc.CONSTRAINT_NAME AS FK_NAME,
ku.TABLE_NAME AS FKTABLE_NAME,
ku.COLUMN_NAME AS FKCOLUMN_NAME,
ku.REFERENCED_TABLE_NAME AS PKTABLE_NAME,
ku.REFERENCED_COLUMN_NAME AS PKCOLUMN_NAME,
rc.UPDATE_RULE,
rc.DELETE_RULE
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE ku
ON ku.TABLE_SCHEMA = rc.CONSTRAINT_SCHEMA AND rc.CONSTRAINT_NAME = ku.CONSTRAINT_NAME
WHERE ku.TABLE_SCHEMA = $tableSchema
AND ku.CONSTRAINT_SCHEMA = $tableSchema
AND rc.CONSTRAINT_SCHEMA = $tableSchema
AND $inTableList
ORDER BY ku.ORDINAL_POSITION
""".trimIndent()
) { rs ->
while (rs.next()) {
rs.extractForeignKeys(allTables, true)?.let { (fromTableName, fk) ->
constraintsToLoad.getOrPut(fromTableName) { mutableMapOf() }
.merge(fk.fkName, fk, ForeignKeyConstraint::plus)
}
}
}
// This ensures MySQL/MariaDB have same behavior as before: a map entry for every table even if no FKs
allTables.keys.forEach { constraintsToLoad.putIfAbsent(it, mutableMapOf()) }
constraintsToLoad.mapValues { (_, v) -> v.values.toList() }
} else {
allTables.keys.associateWith { table ->
val (catalog, tableSchema) = tableCatalogAndSchema(allTables[table]!!)
metadata.getImportedKeys(catalog, identifierManager.inProperCase(tableSchema), table)
.iterate { extractForeignKeys(allTables, false) }
.filterNotNull()
.unzip().second
.groupBy { it.fkName }.values
.map { it.reduce(ForeignKeyConstraint::plus) }
}
}
}