Skip to content

Commit

Permalink
feat: EXPOSED-220 Support multiple statements returning a result in e…
Browse files Browse the repository at this point in the history
…xec()

Fix KDocs

Add test that confirms multiple statement exec works with parameterization args.
  • Loading branch information
bog-walk committed Nov 22, 2023
1 parent f0a3767 commit d581da2
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ open class Transaction(
*
* The [explicitStatementType] can be manually set to avoid iterating over [StatementType] values for the best match.
*
* **Note** `StatementType.MULTI` can be provided to enable execution of multiple concatenated statements.
* **Note** `StatementType.MULTI` can be set to enable execution of multiple concatenated statements.
* However, if more than one [ResultSet] is generated, only the first will be used in the [transform] block.
*
* @return The result of [transform] on the [ResultSet] generated by the statement execution,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,12 @@ enum class StatementType(val group: StatementGroup) {
/** An EXEC statement to execute a stored procedure or command. */
EXEC(StatementGroup.DML),

/** A SHOW statement to provide information about database objects. */
SHOW(StatementGroup.DML),

/** A PRAGMA statement to configure or query the internal database state. */
PRAGMA(StatementGroup.DML),

/** A SHOW statement to provide information about database objects. */
SHOW(StatementGroup.DML),

/** Represents multiple statements of mixed types concatenated in a single string. */
MULTI(StatementGroup.DML),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ interface PreparedStatementApi {
* Executes multiple SQL statements stored in a single [PreparedStatement].
*
* @return A list of [StatementResult]s retrieved from the database, which may store either affected row counts
* or [ResultSet]s.
* or [ResultSet]s. The order of elements is based on the order of the statements in the `PreparedStatement`.
*/
fun executeMultiple(): List<StatementResult>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,86 @@
package org.jetbrains.exposed.sql.tests.shared

import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.statements.StatementType
import org.jetbrains.exposed.sql.tests.DatabaseTestsBase
import org.jetbrains.exposed.sql.tests.TestDB
import org.jetbrains.exposed.sql.tests.inProperCase
import org.jetbrains.exposed.sql.transactions.TransactionManager
import org.jetbrains.exposed.sql.transactions.transaction
import org.junit.Assume
import org.junit.Test
import kotlin.test.assertNotNull

class ParameterizationTests : DatabaseTestsBase() {
object TempTable : Table("tmp") {
val name = varchar("foo", 50)
}

@Test
fun testInsertWithQuotesAndGetItBack() {
val table = object : Table("tmp") {
val name = varchar("foo", 50)
}

withTables(table) {
withTables(TempTable) {
exec(
"INSERT INTO ${table.tableName} (foo) VALUES (?)",
"INSERT INTO ${TempTable.tableName} (foo) VALUES (?)",
listOf(VarCharColumnType() to "John \"Johny\" Johnson")
)

assertEquals("John \"Johny\" Johnson", table.selectAll().single()[table.name])
assertEquals("John \"Johny\" Johnson", TempTable.selectAll().single()[TempTable.name])
}
}

@Test
fun testParametersWithMultipleStatements() {
val supported = setOf(TestDB.MYSQL, TestDB.MARIADB, TestDB.POSTGRESQL, TestDB.SQLSERVER)
Assume.assumeTrue(supported.containsAll(TestDB.enabledDialects()))

val dialect = TestDB.enabledDialects().first()
val urlExtra = when (dialect) {
TestDB.MYSQL -> "&allowMultiQueries=true"
TestDB.MARIADB -> "?&allowMultiQueries=true"
else -> ""
}
val db = Database.connect(
dialect.connection.invoke().plus(urlExtra),
dialect.driver,
dialect.user,
dialect.pass
)

transaction(db) {
try {
SchemaUtils.create(TempTable)

val table = TempTable.tableName.inProperCase()
val column = TempTable.name.name.inProperCase()

val result = exec(
"""
INSERT INTO $table ($column) VALUES (?);
INSERT INTO $table ($column) VALUES (?);
INSERT INTO $table ($column) VALUES (?);
DELETE FROM $table WHERE $table.$column LIKE ?;
SELECT COUNT(*) FROM $table;
""".trimIndent(),
args = listOf(
VarCharColumnType() to "Anne",
VarCharColumnType() to "Anya",
VarCharColumnType() to "Anna",
VarCharColumnType() to "Ann%",
),
explicitStatementType = StatementType.MULTI
) { resultSet ->
resultSet.next()
resultSet.getInt(1)
}
assertNotNull(result)
assertEquals(1, result)

assertEquals("Anya", TempTable.selectAll().single()[TempTable.name])
} finally {
SchemaUtils.drop(TempTable)
}
}

TransactionManager.closeAndUnregister(db)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class TransactionExecTests : DatabaseTestsBase() {

val columnAlias = "last_inserted_id"
val selectLastIdStatement = when (testDb) {
TestDB.SQLSERVER -> "SELECT current_value AS $columnAlias FROM sys.sequences"
TestDB.SQLSERVER -> "SELECT current_value AS $columnAlias FROM sys.sequences"
TestDB.ORACLE -> "SELECT ${ExecTable.id.autoIncColumnType?.autoincSeq}.CURRVAL AS $columnAlias FROM DUAL"
TestDB.POSTGRESQL -> "SELECT lastval() AS $columnAlias"
else -> "SELECT LAST_INSERT_ID() AS $columnAlias"
Expand Down

0 comments on commit d581da2

Please sign in to comment.