From 5fc54d42b776da1ed602f6a59f87632437f7d5cc Mon Sep 17 00:00:00 2001 From: Jocelyne <38375996+joc-a@users.noreply.github.com> Date: Mon, 18 Sep 2023 12:35:25 +0200 Subject: [PATCH] fix: EXPOSED-162 SQLite generatedKeys exception (#1854) Support for getGeneratedKeys() was dropped in the sqlite jdbc version 3.43.0.0. This caused a SQLFeatureNotSupportedException when using this version with Exposed, so the old implementation of getGeneratedKeys() was used in Exposed to retain the previous behaviour. --- .../org/jetbrains/exposed/gradle/Versions.kt | 2 +- exposed-jdbc/api/exposed-jdbc.api | 2 +- .../sql/statements/jdbc/JdbcConnectionImpl.kt | 12 +++++++++-- .../jdbc/JdbcPreparedStatementImpl.kt | 21 ++++++++++++++++--- .../shared/functions/MathFunctionTests.kt | 9 ++++++-- 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/buildSrc/src/main/kotlin/org/jetbrains/exposed/gradle/Versions.kt b/buildSrc/src/main/kotlin/org/jetbrains/exposed/gradle/Versions.kt index bf8db43fec..81aac7e4db 100644 --- a/buildSrc/src/main/kotlin/org/jetbrains/exposed/gradle/Versions.kt +++ b/buildSrc/src/main/kotlin/org/jetbrains/exposed/gradle/Versions.kt @@ -17,7 +17,7 @@ object Versions { const val oracle12 = "12.2.0.1" const val postgre = "42.6.0" const val postgreNG = "0.8.9" - const val sqlLite3 = "3.42.0.0" + const val sqlLite3 = "3.43.0.0" const val sqlserver = "9.4.1.jre8" /** Spring **/ diff --git a/exposed-jdbc/api/exposed-jdbc.api b/exposed-jdbc/api/exposed-jdbc.api index ce7bcb56f3..d2401db896 100644 --- a/exposed-jdbc/api/exposed-jdbc.api +++ b/exposed-jdbc/api/exposed-jdbc.api @@ -59,7 +59,7 @@ public final class org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadat } public final class org/jetbrains/exposed/sql/statements/jdbc/JdbcPreparedStatementImpl : org/jetbrains/exposed/sql/statements/api/PreparedStatementApi { - public fun (Ljava/sql/PreparedStatement;Z)V + public fun (Ljava/sql/PreparedStatement;ZZ)V public fun addBatch ()V public fun cancel ()V public fun closeIfPossible ()V diff --git a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcConnectionImpl.kt b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcConnectionImpl.kt index a1ae0d3ad9..4ae31e1116 100644 --- a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcConnectionImpl.kt +++ b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcConnectionImpl.kt @@ -74,11 +74,19 @@ class JdbcConnectionImpl(override val connection: Connection) : ExposedConnectio } else { PreparedStatement.NO_GENERATED_KEYS } - return JdbcPreparedStatementImpl(connection.prepareStatement(sql, generated), returnKeys) + return JdbcPreparedStatementImpl( + connection.prepareStatement(sql, generated), + returnKeys, + connection.metaData.supportsGetGeneratedKeys() + ) } override fun prepareStatement(sql: String, columns: Array): PreparedStatementApi { - return JdbcPreparedStatementImpl(connection.prepareStatement(sql, columns), true) + return JdbcPreparedStatementImpl( + connection.prepareStatement(sql, columns), + true, + connection.metaData.supportsGetGeneratedKeys() + ) } override fun executeInBatch(sqls: List) { diff --git a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcPreparedStatementImpl.kt b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcPreparedStatementImpl.kt index e6edcac443..f09d00f4ee 100644 --- a/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcPreparedStatementImpl.kt +++ b/exposed-jdbc/src/main/kotlin/org/jetbrains/exposed/sql/statements/jdbc/JdbcPreparedStatementImpl.kt @@ -4,18 +4,33 @@ import org.jetbrains.exposed.sql.BinaryColumnType import org.jetbrains.exposed.sql.BlobColumnType import org.jetbrains.exposed.sql.IColumnType import org.jetbrains.exposed.sql.statements.api.PreparedStatementApi +import org.jetbrains.exposed.sql.vendors.SQLiteDialect +import org.jetbrains.exposed.sql.vendors.currentDialect import java.io.InputStream import java.sql.PreparedStatement import java.sql.ResultSet import java.sql.Types -class JdbcPreparedStatementImpl(val statement: PreparedStatement, val wasGeneratedKeysRequested: Boolean) : PreparedStatementApi { +class JdbcPreparedStatementImpl( + val statement: PreparedStatement, + val wasGeneratedKeysRequested: Boolean, + private val supportsGetGeneratedKeys: Boolean +) : PreparedStatementApi { override val resultSet: ResultSet? - get() = if (wasGeneratedKeysRequested) statement.generatedKeys else statement.resultSet + get() = when { + !wasGeneratedKeysRequested -> statement.resultSet + supportsGetGeneratedKeys -> statement.generatedKeys + currentDialect is SQLiteDialect -> { + statement.connection.prepareStatement("select last_insert_rowid();").executeQuery() + } + else -> statement.resultSet + } override var fetchSize: Int? get() = statement.fetchSize - set(value) { value?.let { statement.fetchSize = value } } + set(value) { + value?.let { statement.fetchSize = value } + } override fun addBatch() { statement.addBatch() diff --git a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/functions/MathFunctionTests.kt b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/functions/MathFunctionTests.kt index 56a1171489..46ba5cf2e9 100644 --- a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/functions/MathFunctionTests.kt +++ b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/functions/MathFunctionTests.kt @@ -103,12 +103,17 @@ class MathFunctionTests : FunctionsTestBase() { @Test fun testRoundFunction() { - withTable { + withTable { testDb -> assertExpressionEqual(BigDecimal(10), RoundFunction(intLiteral(10), 0)) assertExpressionEqual(BigDecimal("10.00"), RoundFunction(intLiteral(10), 2)) assertExpressionEqual(BigDecimal(10), RoundFunction(doubleLiteral(10.455), 0)) assertExpressionEqual(BigDecimal(11), RoundFunction(doubleLiteral(10.555), 0)) - assertExpressionEqual(BigDecimal("10.56"), RoundFunction(doubleLiteral(10.555), 2)) + if (testDb == TestDB.SQLITE) { + // Change this when this issue is resolved https://www.sqlite.org/forum/forumpost/2801f84063 + assertExpressionEqual(BigDecimal("10.55"), RoundFunction(doubleLiteral(10.555), 2)) + } else { + assertExpressionEqual(BigDecimal("10.56"), RoundFunction(doubleLiteral(10.555), 2)) + } } }