diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/H2.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/H2.kt index b26c613c3e..bd1f333f0a 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/H2.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/H2.kt @@ -4,6 +4,7 @@ import org.intellij.lang.annotations.Language import org.jetbrains.exposed.exceptions.throwUnsupportedException import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.transactions.TransactionManager +import java.util.* internal object H2DataTypeProvider : DataTypeProvider() { override fun binaryType(): String { @@ -12,6 +13,7 @@ internal object H2DataTypeProvider : DataTypeProvider() { } override fun uuidType(): String = "UUID" + override fun uuidToDB(value: UUID): Any = value.toString() override fun dateTimeType(): String = "DATETIME(9)" override fun timestampWithTimeZoneType(): String = "TIMESTAMP(9) WITH TIME ZONE" 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 42b08283f2..82e1ef05fb 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.util.* internal object OracleDataTypeProvider : DataTypeProvider() { override fun byteType(): String = "SMALLINT" @@ -26,11 +27,25 @@ internal object OracleDataTypeProvider : DataTypeProvider() { override fun binaryType(length: Int): String { @Suppress("MagicNumber") - return if (length < 2000) "RAW ($length)" - else binaryType() + return if (length < 2000) "RAW ($length)" else binaryType() + } + + override fun uuidType(): String { + return if ((currentDialect as? H2Dialect)?.h2Mode == H2Dialect.H2CompatibilityMode.Oracle) { + "UUID" + } else { + return "RAW(16)" + } + } + + override fun uuidToDB(value: UUID): Any { + return if ((currentDialect as? H2Dialect)?.h2Mode == H2Dialect.H2CompatibilityMode.Oracle) { + H2DataTypeProvider.uuidToDB(value) + } else { + super.uuidToDB(value) + } } - override fun uuidType(): String = "RAW(16)" override fun dateTimeType(): String = "TIMESTAMP" override fun booleanType(): String = "CHAR(1)" override fun booleanToStatementString(bool: Boolean) = if (bool) "1" else "0" diff --git a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/dml/UpsertTests.kt b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/dml/UpsertTests.kt index ba24fdbbf1..554f95a621 100644 --- a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/dml/UpsertTests.kt +++ b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/dml/UpsertTests.kt @@ -63,17 +63,17 @@ class UpsertTests : DatabaseTestsBase() { it[name] = "A" } - tester.upsert { // insert because only 1 constraint is equal + tester.upsert { // insert because only 1 constraint is equal it[idA] = 7 it[idB] = insertStmt get tester.idB it[name] = "B" } - tester.upsert { // insert because both constraints differ + tester.upsert { // insert because both constraints differ it[idA] = 99 it[idB] = 99 it[name] = "C" } - tester.upsert { // update because both constraints match + tester.upsert { // update because both constraints match it[idA] = insertStmt get tester.idA it[idB] = insertStmt get tester.idB it[name] = "D" @@ -157,6 +157,32 @@ class UpsertTests : DatabaseTestsBase() { } } + @Test + fun testUpsertWithUUIDKeyConflict() { + val tester = object : Table("tester") { + val id = uuid("id").autoGenerate() + val title = text("title") + + override val primaryKey = PrimaryKey(id) + } + + withTables(tester) { testDb -> + excludingH2Version1(testDb) { + val uuid1 = tester.upsert { + it[title] = "A" + } get tester.id + tester.upsert { + it[id] = uuid1 + it[title] = "B" + } + + val result = tester.selectAll().single() + assertEquals(uuid1, result[tester.id]) + assertEquals("B", result[tester.title]) + } + } + } + @Test fun testUpsertWithNoUniqueConstraints() { val tester = object : Table("tester") { @@ -254,18 +280,18 @@ class UpsertTests : DatabaseTestsBase() { withTables(tester) { testDb -> excludingH2Version1(testDb) { val testWord = "Test" - tester.upsert { // default expression in insert + tester.upsert { // default expression in insert it[word] = testWord } assertEquals("Phrase", tester.selectAll().single()[tester.phrase]) val phraseConcat = concat(" - ", listOf(tester.word, tester.phrase)) - tester.upsert(onUpdate = listOf(tester.phrase to phraseConcat)) { // expression in update + tester.upsert(onUpdate = listOf(tester.phrase to phraseConcat)) { // expression in update it[word] = testWord } assertEquals("$testWord - $defaultPhrase", tester.selectAll().single()[tester.phrase]) - tester.upsert { // provided expression in insert + tester.upsert { // provided expression in insert it[word] = "$testWord 2" it[phrase] = concat(stringLiteral("foo"), stringLiteral("bar")) }