in exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/v1/jdbc/statements/jdbc/JdbcDatabaseMetadataImpl.kt [229:293]
override fun existingIndices(vararg tables: Table): Map<Table, List<Index>> {
for (table in tables) {
val transaction = TransactionManager.current()
val (catalog, tableSchema) = tableCatalogAndSchema(table)
existingIndicesCache.getOrPut(table) {
val pkNames = metadata.getPrimaryKeys(
catalog,
tableSchema,
table.nameInDatabaseCaseUnquoted()
).let { rs ->
val names = arrayListOf<String>()
while (rs.next()) {
rs.getString("PK_NAME")?.let { names += it }
}
rs.close()
names
}
val storedIndexTable = if
(tableSchema == currentSchema!! && currentDialect is OracleDialect) {
table.nameInDatabaseCase()
} else {
table.nameInDatabaseCaseUnquoted()
}
val rs = metadata.getIndexInfo(catalog, tableSchema, storedIndexTable, false, false)
val tmpIndices = hashMapOf<Triple<String, Boolean, Op.TRUE?>, MutableList<String>>()
while (rs.next()) {
rs.getString("INDEX_NAME")?.let { indexName ->
// if index is function-based, SQLite & MySQL return null column_name metadata
val columnNameMetadata = rs.getString("COLUMN_NAME") ?: when (currentDialect) {
is MysqlDialect, is SQLiteDialect -> "\"\""
else -> null
}
columnNameMetadata?.let { columnName ->
val column = transaction.db.identifierManager.quoteIdentifierWhenWrongCaseOrNecessary(
columnName
)
val isUnique = !rs.getBoolean("NON_UNIQUE")
val isPartial = if (rs.getString("FILTER_CONDITION").isNullOrEmpty()) null else Op.TRUE
tmpIndices.getOrPut(Triple(indexName, isUnique, isPartial)) { arrayListOf() }.add(column)
}
}
}
rs.close()
val tColumns = table.columns.associateBy { transaction.identity(it) }
tmpIndices.filterNot { it.key.first in pkNames }.mapNotNull { (index, columns) ->
val (functionBased, columnBased) = columns.distinct().partition { cn -> tColumns[cn] == null }
columnBased.map { cn -> tColumns[cn]!! }.takeIf { c -> c.size + functionBased.size == columns.size }?.let { c ->
Index(
c,
index.second,
index.first,
filterCondition = index.third,
functions = functionBased.map { stringLiteral(it) }.ifEmpty { null },
functionsTable = if (functionBased.isNotEmpty()) table else null
)
}
}
}
}
return HashMap(existingIndicesCache)
}