diff --git a/exposed-core/api/exposed-core.api b/exposed-core/api/exposed-core.api index b9a2ce27c6..8a1dd9a39e 100644 --- a/exposed-core/api/exposed-core.api +++ b/exposed-core/api/exposed-core.api @@ -1677,7 +1677,6 @@ public final class org/jetbrains/exposed/sql/Rank : org/jetbrains/exposed/sql/Wi public final class org/jetbrains/exposed/sql/ReferenceOption : java/lang/Enum { public static final field CASCADE Lorg/jetbrains/exposed/sql/ReferenceOption; - public static final field Companion Lorg/jetbrains/exposed/sql/ReferenceOption$Companion; public static final field NO_ACTION Lorg/jetbrains/exposed/sql/ReferenceOption; public static final field RESTRICT Lorg/jetbrains/exposed/sql/ReferenceOption; public static final field SET_DEFAULT Lorg/jetbrains/exposed/sql/ReferenceOption; @@ -1687,10 +1686,6 @@ public final class org/jetbrains/exposed/sql/ReferenceOption : java/lang/Enum { public static fun values ()[Lorg/jetbrains/exposed/sql/ReferenceOption; } -public final class org/jetbrains/exposed/sql/ReferenceOption$Companion { - public final fun resolveRefOptionFromJdbc (I)Lorg/jetbrains/exposed/sql/ReferenceOption; -} - public final class org/jetbrains/exposed/sql/RegexpOp : org/jetbrains/exposed/sql/Op, org/jetbrains/exposed/sql/ComplexExpression, org/jetbrains/exposed/sql/Op$OpBoolean { public fun (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;Z)V public final fun getCaseSensitive ()Z @@ -3265,6 +3260,7 @@ public abstract interface class org/jetbrains/exposed/sql/vendors/DatabaseDialec public abstract fun modifyColumn (Lorg/jetbrains/exposed/sql/Column;Lorg/jetbrains/exposed/sql/ColumnDiff;)Ljava/util/List; public abstract fun resetCaches ()V public abstract fun resetSchemaCaches ()V + public abstract fun resolveRefOptionFromJdbc (I)Lorg/jetbrains/exposed/sql/ReferenceOption; public abstract fun schemaExists (Lorg/jetbrains/exposed/sql/Schema;)Z public abstract fun setSchema (Lorg/jetbrains/exposed/sql/Schema;)Ljava/lang/String; public abstract fun supportsSelectForUpdate ()Z @@ -3305,6 +3301,7 @@ public final class org/jetbrains/exposed/sql/vendors/DatabaseDialect$DefaultImpl public static fun getSupportsWindowFrameGroupsMode (Lorg/jetbrains/exposed/sql/vendors/DatabaseDialect;)Z public static fun isAllowedAsColumnDefault (Lorg/jetbrains/exposed/sql/vendors/DatabaseDialect;Lorg/jetbrains/exposed/sql/Expression;)Z public static fun listDatabases (Lorg/jetbrains/exposed/sql/vendors/DatabaseDialect;)Ljava/lang/String; + public static fun resolveRefOptionFromJdbc (Lorg/jetbrains/exposed/sql/vendors/DatabaseDialect;I)Lorg/jetbrains/exposed/sql/ReferenceOption; public static fun setSchema (Lorg/jetbrains/exposed/sql/vendors/DatabaseDialect;Lorg/jetbrains/exposed/sql/Schema;)Ljava/lang/String; public static fun tableColumns (Lorg/jetbrains/exposed/sql/vendors/DatabaseDialect;[Lorg/jetbrains/exposed/sql/Table;)Ljava/util/Map; } @@ -3564,6 +3561,7 @@ public class org/jetbrains/exposed/sql/vendors/OracleDialect : org/jetbrains/exp public fun isAllowedAsColumnDefault (Lorg/jetbrains/exposed/sql/Expression;)Z public fun listDatabases ()Ljava/lang/String; public fun modifyColumn (Lorg/jetbrains/exposed/sql/Column;Lorg/jetbrains/exposed/sql/ColumnDiff;)Ljava/util/List; + public fun resolveRefOptionFromJdbc (I)Lorg/jetbrains/exposed/sql/ReferenceOption; public fun setSchema (Lorg/jetbrains/exposed/sql/Schema;)Ljava/lang/String; } @@ -3710,6 +3708,7 @@ public abstract class org/jetbrains/exposed/sql/vendors/VendorDialect : org/jetb protected final fun quoteIdentifierWhenWrongCaseOrNecessary (Ljava/lang/String;Lorg/jetbrains/exposed/sql/Transaction;)Ljava/lang/String; public fun resetCaches ()V public fun resetSchemaCaches ()V + public fun resolveRefOptionFromJdbc (I)Lorg/jetbrains/exposed/sql/ReferenceOption; public fun schemaExists (Lorg/jetbrains/exposed/sql/Schema;)Z public fun setSchema (Lorg/jetbrains/exposed/sql/Schema;)Ljava/lang/String; public fun supportsSelectForUpdate ()Z diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Constraints.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Constraints.kt index 737be6071e..069271bd00 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Constraints.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Constraints.kt @@ -7,7 +7,6 @@ import org.jetbrains.exposed.sql.vendors.SQLiteDialect import org.jetbrains.exposed.sql.vendors.currentDialect import org.jetbrains.exposed.sql.vendors.currentDialectIfAvailable import org.jetbrains.exposed.sql.vendors.inProperCase -import java.sql.DatabaseMetaData /** * Common interface for database objects that can be created, modified and dropped. @@ -36,18 +35,6 @@ enum class ReferenceOption { SET_DEFAULT; override fun toString(): String = name.replace("_", " ") - - companion object { - /** Returns the corresponding [ReferenceOption] for the specified [refOption] from JDBC. */ - fun resolveRefOptionFromJdbc(refOption: Int): ReferenceOption = when (refOption) { - DatabaseMetaData.importedKeyCascade -> CASCADE - DatabaseMetaData.importedKeySetNull -> SET_NULL - DatabaseMetaData.importedKeyRestrict -> RESTRICT - DatabaseMetaData.importedKeyNoAction -> NO_ACTION - DatabaseMetaData.importedKeySetDefault -> SET_DEFAULT - else -> currentDialect.defaultReferenceOption - } - } } /** diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/DatabaseDialect.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/DatabaseDialect.kt index ea394cbd6b..cc8448b733 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/DatabaseDialect.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/DatabaseDialect.kt @@ -2,6 +2,7 @@ package org.jetbrains.exposed.sql.vendors import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.TransactionManager +import java.sql.DatabaseMetaData /** * Common interface for all database dialects. @@ -145,6 +146,16 @@ interface DatabaseDialect { } } + /** Returns the corresponding [ReferenceOption] for the specified [refOption] from JDBC. */ + fun resolveRefOptionFromJdbc(refOption: Int): ReferenceOption = when (refOption) { + DatabaseMetaData.importedKeyCascade -> ReferenceOption.CASCADE + DatabaseMetaData.importedKeySetNull -> ReferenceOption.SET_NULL + DatabaseMetaData.importedKeyRestrict -> ReferenceOption.RESTRICT + DatabaseMetaData.importedKeyNoAction -> ReferenceOption.NO_ACTION + DatabaseMetaData.importedKeySetDefault -> ReferenceOption.SET_DEFAULT + else -> currentDialect.defaultReferenceOption + } + companion object { private val defaultLikePatternSpecialChars = mapOf('%' to null, '_' to null) } diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/OracleDialect.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/OracleDialect.kt index 4b7d8c08bf..fa41799995 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/OracleDialect.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/OracleDialect.kt @@ -3,6 +3,7 @@ package org.jetbrains.exposed.sql.vendors import org.jetbrains.exposed.exceptions.throwUnsupportedException import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.TransactionManager +import java.sql.DatabaseMetaData import java.util.* internal object OracleDataTypeProvider : DataTypeProvider() { @@ -366,5 +367,16 @@ open class OracleDialect : VendorDialect(dialectName, OracleDataTypeProvider, Or } } + /** + * The SQL that gets the constraint information for Oracle returns a 1 for NO ACTION and does not support RESTRICT. + * `decode (f.delete_rule, 'CASCADE', 0, 'SET NULL', 2, 1) as delete_rule` + */ + override fun resolveRefOptionFromJdbc(refOption: Int): ReferenceOption = when (refOption) { + DatabaseMetaData.importedKeyCascade -> ReferenceOption.CASCADE + DatabaseMetaData.importedKeySetNull -> ReferenceOption.SET_NULL + DatabaseMetaData.importedKeyRestrict -> ReferenceOption.NO_ACTION + else -> currentDialect.defaultReferenceOption + } + companion object : DialectNameProvider("Oracle") } diff --git a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt index 5e788724eb..fc94340607 100644 --- a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt +++ b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadataImpl.kt @@ -288,9 +288,9 @@ class JdbcDatabaseMetadataImpl(database: String, val metadata: DatabaseMetaData) identifierManager.quoteIdentifierWhenWrongCaseOrNecessary(it.nameInDatabaseCase()) == targetColumnName } ?: return@iterate null // Do not crash if there are missing fields in Exposed's tables val constraintUpdateRule = getObject("UPDATE_RULE")?.toString()?.toIntOrNull()?.let { - ReferenceOption.resolveRefOptionFromJdbc(it) + currentDialect.resolveRefOptionFromJdbc(it) } - val constraintDeleteRule = ReferenceOption.resolveRefOptionFromJdbc(getInt("DELETE_RULE")) + val constraintDeleteRule = currentDialect.resolveRefOptionFromJdbc(getInt("DELETE_RULE")) ForeignKeyConstraint( target = targetColumn, from = fromColumn, diff --git a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/sqlite/ForeignKeyConstraintTests.kt b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/sqlite/ForeignKeyConstraintTests.kt index dfe1da327f..0a00115aba 100644 --- a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/sqlite/ForeignKeyConstraintTests.kt +++ b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/sqlite/ForeignKeyConstraintTests.kt @@ -171,7 +171,7 @@ class ForeignKeyConstraintTests : DatabaseTestsBase() { } @Test - fun testUpdateRuleReadCorrectlyWhenNotSpecifiedInChildTable() { + fun testUpdateAndDeleteRulesReadCorrectlyWhenNotSpecifiedInChildTable() { val category = object : Table("Category") { val id = integer("id") @@ -193,9 +193,14 @@ class ForeignKeyConstraintTests : DatabaseTestsBase() { constraints.values.forEach { list -> list.forEach { when (testDb) { - TestDB.H2_ORACLE, TestDB.H2_SQLSERVER -> + TestDB.H2_ORACLE, TestDB.H2_SQLSERVER -> { assertEquals(ReferenceOption.RESTRICT, it.updateRule) - else -> assertEquals(currentDialectTest.defaultReferenceOption, it.updateRule) + assertEquals(ReferenceOption.RESTRICT, it.deleteRule) + } + else -> { + assertEquals(currentDialectTest.defaultReferenceOption, it.updateRule) + assertEquals(currentDialectTest.defaultReferenceOption, it.deleteRule) + } } } } @@ -204,7 +209,7 @@ class ForeignKeyConstraintTests : DatabaseTestsBase() { } @Test - fun testUpdateRuleReadCorrectlyWhenSpecifiedInChildTable() { + fun testUpdateAndDeleteRulesReadCorrectlyWhenSpecifiedInChildTable() { val category = object : Table("Category") { val id = integer("id") @@ -213,7 +218,12 @@ class ForeignKeyConstraintTests : DatabaseTestsBase() { val item = object : Table("Item") { val id = integer("id") - val categoryId = integer("categoryId").references(category.id, onUpdate = ReferenceOption.CASCADE) + val categoryId = integer("categoryId") + .references( + category.id, + onUpdate = ReferenceOption.CASCADE, + onDelete = ReferenceOption.CASCADE + ) override val primaryKey = PrimaryKey(id) } @@ -226,6 +236,7 @@ class ForeignKeyConstraintTests : DatabaseTestsBase() { constraints.values.forEach { list -> list.forEach { assertEquals(ReferenceOption.CASCADE, it.updateRule) + assertEquals(ReferenceOption.CASCADE, it.deleteRule) } } }