Skip to content

Commit

Permalink
#394 Foreign Key Constraints being recreated
Browse files Browse the repository at this point in the history
  • Loading branch information
Tapac committed Oct 26, 2018
1 parent 0908b54 commit 7569ad8
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 12 deletions.
14 changes: 7 additions & 7 deletions src/main/kotlin/org/jetbrains/exposed/sql/Queries.kt
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,7 @@ fun checkExcessiveIndices(vararg tables: Table) {

if (!excessiveConstraints.isEmpty()) {
exposedLogger.warn("List of excessive foreign key constraints:")
excessiveConstraints.forEach {
val (pair, fk) = it
excessiveConstraints.forEach { (pair, fk) ->
val constraint = fk.first()
exposedLogger.warn("\t\t\t'${pair.first}'.'${pair.second}' -> '${constraint.fromTable}'.'${constraint.fromColumn}':\t${fk.joinToString(", ") {it.fkName}}")
}
Expand Down Expand Up @@ -197,15 +196,16 @@ private fun checkMissingIndices(vararg tables: Table): List<Index> {
}
}

val tr = TransactionManager.current()
val fKeyConstraints = currentDialect.columnConstraints(*tables).keys

fun List<Index>.filterFKeys() = filterNot { (it.table.tableName.inProperCase() to it.columns.singleOrNull()?.name?.inProperCase()) in fKeyConstraints }
val existingIndices = currentDialect.existingIndices(*tables)
fun List<Index>.filterFKeys() = filterNot { (it.table.tableName.inProperCase() to it.columns.singleOrNull()?.let { c -> tr.identity(c) }) in fKeyConstraints }

val missingIndices = HashSet<Index>()
val notMappedIndices = HashMap<String, MutableSet<Index>>()
val nameDiffers = HashSet<Index>()
for (table in tables) {
val existingTableIndices = currentDialect.existingIndices(table)[table].orEmpty().filterFKeys()
val existingTableIndices = existingIndices[table].orEmpty().filterFKeys()
val mappedIndices = table.indices.filterFKeys()

existingTableIndices.forEach { index ->
Expand All @@ -216,13 +216,13 @@ private fun checkMissingIndices(vararg tables: Table): List<Index> {
}
}

notMappedIndices.getOrPut(table.nameInDatabaseCase(), {hashSetOf()}).addAll(existingTableIndices.subtract(mappedIndices))
notMappedIndices.getOrPut(table.nameInDatabaseCase()) {hashSetOf()}.addAll(existingTableIndices.subtract(mappedIndices))

missingIndices.addAll(mappedIndices.subtract(existingTableIndices))
}

val toCreate = missingIndices.subtract(nameDiffers)
toCreate.log("Indices missed from database (will be created):")
notMappedIndices.forEach { e -> e.value.subtract(nameDiffers).log("Indices exist in database and not mapped in code on class '${e.key}':") }
notMappedIndices.forEach { (name, indexes) -> indexes.subtract(nameDiffers).log("Indices exist in database and not mapped in code on class '$name':") }
return toCreate.toList()
}
2 changes: 1 addition & 1 deletion src/main/kotlin/org/jetbrains/exposed/sql/SchemaUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ object SchemaUtils {
for (table in tables) {
for (column in table.columns) {
if (column.referee != null) {
val existingConstraint = existingColumnConstraint[table.tableName.inProperCase() to column.name.inProperCase()]?.firstOrNull()
val existingConstraint = existingColumnConstraint[table.tableName.inProperCase() to identity(column)]?.firstOrNull()
if (existingConstraint == null) {
statements.addAll(createFKey(column))
} else if (existingConstraint.targetTable != column.referee!!.table.tableName.inProperCase()
Expand Down
14 changes: 10 additions & 4 deletions src/main/kotlin/org/jetbrains/exposed/sql/vendors/Default.kt
Original file line number Diff line number Diff line change
Expand Up @@ -252,16 +252,22 @@ abstract class VendorDialect(override val name: String,
@Synchronized
override fun columnConstraints(vararg tables: Table): Map<Pair<String, String>, List<ForeignKeyConstraint>> {
val constraints = HashMap<Pair<String, String>, MutableList<ForeignKeyConstraint>>()
for (table in tables.map{ it.nameInDatabaseCase() }) {
val tr = TransactionManager.current()
val db = tr.db
val q = db.identityQuoteString

fun String.quoteIfNeeded() = if (db.shouldQuoteIdentifiers && inProperCase != this) "$q$this$q" else tr.quoteIfNecessary(this)

tables.map{ it.nameInDatabaseCase() }.forEach { table ->
columnConstraintsCache.getOrPut(table) {
val rs = TransactionManager.current().db.metadata.getImportedKeys(getDatabase(), null, table)
val rs = db.metadata.getImportedKeys(getDatabase(), null, table)
val tableConstraint = arrayListOf<ForeignKeyConstraint> ()
while (rs.next()) {
val fromTableName = rs.getString("FKTABLE_NAME")!!
val fromColumnName = rs.getString("FKCOLUMN_NAME")!!
val fromColumnName = rs.getString("FKCOLUMN_NAME")!!.quoteIfNeeded()
val constraintName = rs.getString("FK_NAME")!!
val targetTableName = rs.getString("PKTABLE_NAME")!!
val targetColumnName = rs.getString("PKCOLUMN_NAME")!!
val targetColumnName = rs.getString("PKCOLUMN_NAME")!!.quoteIfNeeded()
val constraintUpdateRule = ReferenceOption.resolveRefOptionFromJdbc(rs.getInt("UPDATE_RULE"))
val constraintDeleteRule = ReferenceOption.resolveRefOptionFromJdbc(rs.getInt("DELETE_RULE"))
tableConstraint.add(
Expand Down

0 comments on commit 7569ad8

Please sign in to comment.