From 6c087a46fd9c434c526ac879830caa71f5343223 Mon Sep 17 00:00:00 2001 From: Chantal Loncle <82039410+bog-walk@users.noreply.github.com> Date: Mon, 7 Aug 2023 06:39:14 -0400 Subject: [PATCH] fix: EXPOSED-128 Update with Join and Where clause fails in Oracle The following test fails when run on Oracle: UpdateTests/testUpdateWithJoinAndWhere() Fails with an assertion error because the arguments passed to PreparedStatement are in the wrong positions. This happens because Oracle is the only supported database to use a subquery directly in the UPDATE syntax to represent the join part and the WHERE clause together. And, unlike other DB, this WHERE clause also comes before the UPDATE set clause. Fixed by reversing the order of arguments in the UpdateStatement query builder, specifically when an update-with-join operation is executed. --- .../exposed/sql/statements/UpdateStatement.kt | 15 ++++++++++++--- .../exposed/sql/vendors/OracleDialect.kt | 2 +- .../exposed/sql/tests/shared/dml/UpdateTests.kt | 1 + 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/statements/UpdateStatement.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/statements/UpdateStatement.kt index 2bdc003f29..0e4c7254ae 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/statements/UpdateStatement.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/statements/UpdateStatement.kt @@ -5,6 +5,8 @@ import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.statements.api.PreparedStatementApi import org.jetbrains.exposed.sql.vendors.H2Dialect.H2CompatibilityMode import org.jetbrains.exposed.sql.vendors.H2FunctionProvider +import org.jetbrains.exposed.sql.vendors.OracleDialect +import org.jetbrains.exposed.sql.vendors.currentDialect import org.jetbrains.exposed.sql.vendors.h2Mode open class UpdateStatement(val targetsSet: ColumnSet, val limit: Int?, val where: Op? = null) : @@ -35,10 +37,17 @@ open class UpdateStatement(val targetsSet: ColumnSet, val limit: Int?, val where } override fun arguments(): Iterable>> = QueryBuilder(true).run { - values.forEach { - registerArgument(it.key, it.value) + if (targetsSet is Join && currentDialect is OracleDialect) { + where?.toQueryBuilder(this) + values.forEach { + registerArgument(it.key, it.value) + } + } else { + values.forEach { + registerArgument(it.key, it.value) + } + where?.toQueryBuilder(this) } - where?.toQueryBuilder(this) if (args.isNotEmpty()) listOf(args) else emptyList() } } 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 82e1ef05fb..90ec7b6f11 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 @@ -252,7 +252,7 @@ internal object OracleFunctionProvider : FunctionProvider() { } limit?.let { - "WHERE ROWNUM <= $it" + +" WHERE ROWNUM <= $it" } toString() diff --git a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/dml/UpdateTests.kt b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/dml/UpdateTests.kt index c8e8b56bc5..dccd460766 100644 --- a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/dml/UpdateTests.kt +++ b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/dml/UpdateTests.kt @@ -85,6 +85,7 @@ class UpdateTests : DatabaseTestsBase() { } } } + @Test fun testUpdateWithJoin02() { withCitiesAndUsers(exclude = TestDB.allH2TestDB + TestDB.SQLITE) { cities, users, userData ->