Skip to content

Commit

Permalink
fix: EXPOSED-173 UPDATE_RULE read incorrectly for Oracle (JetBrains#1865
Browse files Browse the repository at this point in the history
)

In Oracle, update_rule is hardcoded to NULL, which gets converted to 0 when using getInt("UPDATE_RULE"), and is then mistakenly taken to represent DatabaseMetaData.importedKeyCascade = 0.
  • Loading branch information
joc-a authored and saral committed Oct 3, 2023
1 parent 7276a26 commit 77b7a1f
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,9 @@ class JdbcDatabaseMetadataImpl(database: String, val metadata: DatabaseMetaData)
val targetColumn = allTables[targetTableName]?.columns?.firstOrNull {
identifierManager.quoteIdentifierWhenWrongCaseOrNecessary(it.nameInDatabaseCase()) == targetColumnName
} ?: return@iterate null // Do not crash if there are missing fields in Exposed's tables
val constraintUpdateRule = ReferenceOption.resolveRefOptionFromJdbc(getInt("UPDATE_RULE"))
val constraintUpdateRule = getObject("UPDATE_RULE")?.toString()?.toIntOrNull()?.let {
ReferenceOption.resolveRefOptionFromJdbc(it)
}
val constraintDeleteRule = ReferenceOption.resolveRefOptionFromJdbc(getInt("DELETE_RULE"))
ForeignKeyConstraint(
target = targetColumn,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.tests.DatabaseTestsBase
import org.jetbrains.exposed.sql.tests.TestDB
import org.jetbrains.exposed.sql.tests.currentDialectTest
import org.jetbrains.exposed.sql.tests.shared.Category
import org.jetbrains.exposed.sql.tests.shared.DEFAULT_CATEGORY_ID
import org.jetbrains.exposed.sql.tests.shared.Item
Expand All @@ -27,7 +28,13 @@ class ForeignKeyConstraintTests : DatabaseTestsBase() {
fun `test ON DELETE SET DEFAULT for SQLite`() {
Assume.assumeTrue(TestDB.SQLITE in TestDB.enabledDialects())

transaction(Database.connect("jdbc:sqlite:file:test?mode=memory&cache=shared&foreign_keys=on", user = "root", driver = "org.sqlite.JDBC")) {
transaction(
Database.connect(
"jdbc:sqlite:file:test?mode=memory&cache=shared&foreign_keys=on",
user = "root",
driver = "org.sqlite.JDBC"
)
) {
testOnDeleteSetDefault()
}
}
Expand Down Expand Up @@ -80,7 +87,13 @@ class ForeignKeyConstraintTests : DatabaseTestsBase() {
fun `test ON DELETE RESTRICT for SQLite`() {
Assume.assumeTrue(TestDB.SQLITE in TestDB.enabledDialects())

transaction(Database.connect("jdbc:sqlite:file:test?mode=memory&cache=shared&foreign_keys=on", user = "root", driver = "org.sqlite.JDBC")) {
transaction(
Database.connect(
"jdbc:sqlite:file:test?mode=memory&cache=shared&foreign_keys=on",
user = "root",
driver = "org.sqlite.JDBC"
)
) {
testRestrict(isTestingOnDelete = true)
}
}
Expand All @@ -96,7 +109,13 @@ class ForeignKeyConstraintTests : DatabaseTestsBase() {
fun `test ON UPDATE RESTRICT for SQLite`() {
Assume.assumeTrue(TestDB.SQLITE in TestDB.enabledDialects())

transaction(Database.connect("jdbc:sqlite:file:test?mode=memory&cache=shared&foreign_keys=on", user = "root", driver = "org.sqlite.JDBC")) {
transaction(
Database.connect(
"jdbc:sqlite:file:test?mode=memory&cache=shared&foreign_keys=on",
user = "root",
driver = "org.sqlite.JDBC"
)
) {
testRestrict(isTestingOnDelete = false)
}
}
Expand Down Expand Up @@ -150,4 +169,66 @@ class ForeignKeyConstraintTests : DatabaseTestsBase() {
}
}
}

@Test
fun testUpdateRuleReadCorrectlyWhenNotSpecifiedInChildTable() {
val category = object : Table("Category") {
val id = integer("id")

override val primaryKey = PrimaryKey(id)
}

val item = object : Table("Item") {
val id = integer("id")
val categoryId = integer("categoryId").references(category.id)

override val primaryKey = PrimaryKey(id)
}

withTables(category, item) { testDb ->
if (currentDialectTest.supportsOnUpdate) {
val constraints = connection.metadata {
tableConstraints(listOf(item))
}
constraints.values.forEach { list ->
list.forEach {
when (testDb) {
TestDB.H2_ORACLE, TestDB.H2_SQLSERVER ->
assertEquals(ReferenceOption.RESTRICT, it.updateRule)
else -> assertEquals(currentDialectTest.defaultReferenceOption, it.updateRule)
}
}
}
}
}
}

@Test
fun testUpdateRuleReadCorrectlyWhenSpecifiedInChildTable() {
val category = object : Table("Category") {
val id = integer("id")

override val primaryKey = PrimaryKey(id)
}

val item = object : Table("Item") {
val id = integer("id")
val categoryId = integer("categoryId").references(category.id, onUpdate = ReferenceOption.CASCADE)

override val primaryKey = PrimaryKey(id)
}

withTables(category, item) {
if (currentDialectTest.supportsOnUpdate) {
val constraints = connection.metadata {
tableConstraints(listOf(item))
}
constraints.values.forEach { list ->
list.forEach {
assertEquals(ReferenceOption.CASCADE, it.updateRule)
}
}
}
}
}
}

0 comments on commit 77b7a1f

Please sign in to comment.