Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: EXPOSED-709 Remove plain SQL execution from core DatabaseDi…
Browse files Browse the repository at this point in the history
…alect

In preparation fro R2DBC, the following instances of JDBC transaction-specific execution
 have been removed from the core module:
- Retrieving H2 mode
- Retrieving all sequences in the database
bog-walk committed Jan 29, 2025

Verified

This commit was signed with the committer’s verified signature.
1 parent e622c7c commit 2633138
Showing 8 changed files with 57 additions and 62 deletions.
5 changes: 2 additions & 3 deletions exposed-core/api/exposed-core.api
Original file line number Diff line number Diff line change
@@ -3582,6 +3582,7 @@ public abstract class org/jetbrains/exposed/sql/statements/api/ExposedDatabaseMe
public abstract fun existingPrimaryKeys ([Lorg/jetbrains/exposed/sql/Table;)Ljava/util/Map;
public abstract fun existingSequences ([Lorg/jetbrains/exposed/sql/Table;)Ljava/util/Map;
public final fun getDatabase ()Ljava/lang/String;
public abstract fun getDatabaseDialectMode ()Ljava/lang/String;
public abstract fun getDatabaseDialectName ()Ljava/lang/String;
public abstract fun getDatabaseProductVersion ()Ljava/lang/String;
public abstract fun getDefaultIsolationLevel ()I
@@ -3620,6 +3621,7 @@ public abstract class org/jetbrains/exposed/sql/statements/api/IdentifierManager
protected abstract fun getSupportsMixedIdentifiers ()Z
protected abstract fun getSupportsMixedQuotedIdentifiers ()Z
public final fun inProperCase (Ljava/lang/String;)Ljava/lang/String;
public final fun isDotPrefixedAndUnquoted (Ljava/lang/String;)Z
protected abstract fun isLowerCaseIdentifiers ()Z
protected abstract fun isLowerCaseQuotedIdentifiers ()Z
protected abstract fun isUpperCaseIdentifiers ()Z
@@ -4134,7 +4136,6 @@ public class org/jetbrains/exposed/sql/vendors/H2Dialect : org/jetbrains/exposed
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 sequences ()Ljava/util/List;
public fun toString ()Ljava/lang/String;
}

@@ -4230,7 +4231,6 @@ public class org/jetbrains/exposed/sql/vendors/OracleDialect : org/jetbrains/exp
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 sequences ()Ljava/util/List;
public fun setSchema (Lorg/jetbrains/exposed/sql/Schema;)Ljava/lang/String;
}

@@ -4302,7 +4302,6 @@ public class org/jetbrains/exposed/sql/vendors/SQLServerDialect : org/jetbrains/
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 sequences ()Ljava/util/List;
public fun setSchema (Lorg/jetbrains/exposed/sql/Schema;)Ljava/lang/String;
}

Original file line number Diff line number Diff line change
@@ -28,6 +28,9 @@ abstract class ExposedDatabaseMetadata(val database: String) {
/** The name of the database based on the name of the underlying JDBC driver. */
abstract val databaseDialectName: String

/** The name of the mode of the database. This is currently applicable only to H2 databases. */
abstract val databaseDialectMode: String?

/** The version number of the database product as a `String`. */
abstract val databaseProductVersion: String

Original file line number Diff line number Diff line change
@@ -126,13 +126,16 @@ abstract class IdentifierManagerApi {

/** Returns an SQL token wrapped in quotations, if validated as necessary. */
fun quoteIfNecessary(identity: String): String {
return if (identity.contains('.') && !identity.isAlreadyQuoted()) {
return if (isDotPrefixedAndUnquoted(identity)) {
identity.split('.').joinToString(".") { quoteTokenIfNecessary(it) }
} else {
quoteTokenIfNecessary(identity)
}
}

/** Returns whether an [identity] is both unquoted and contains dot characters. */
fun isDotPrefixedAndUnquoted(identity: String): Boolean = identity.contains('.') && !identity.isAlreadyQuoted()

/** Returns an [identity] wrapped in quotations, if validated as necessary. */
fun quoteIdentifierWhenWrongCaseOrNecessary(identity: String): String {
val inProperCase = inProperCase(identity)
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.jetbrains.exposed.sql.vendors

import org.intellij.lang.annotations.Language
import org.jetbrains.exposed.exceptions.throwUnsupportedException
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.statements.StatementType
@@ -260,17 +259,7 @@ open class H2Dialect : VendorDialect(dialectName, H2DataTypeProvider, H2Function

/** The H2 database compatibility mode retrieved from metadata. */
val h2Mode: H2CompatibilityMode? by lazy {
val (settingNameField, settingValueField) = when (majorVersion) {
H2MajorVersion.One -> "NAME" to "VALUE"
H2MajorVersion.Two -> "SETTING_NAME" to "SETTING_VALUE"
}

@Language("H2")
val fetchModeQuery = "SELECT $settingValueField FROM INFORMATION_SCHEMA.SETTINGS WHERE $settingNameField = 'MODE'"
val modeValue = TransactionManager.current().exec(fetchModeQuery) { rs ->
rs.next()
rs.getString(settingValueField)
}
val modeValue = TransactionManager.current().db.metadata { databaseDialectMode }
when {
modeValue == null -> null
modeValue.equals("MySQL", ignoreCase = true) -> H2CompatibilityMode.MySQL
@@ -355,23 +344,6 @@ open class H2Dialect : VendorDialect(dialectName, H2DataTypeProvider, H2Function
}
}

override fun sequences(): List<String> {
val sequences = mutableListOf<String>()
TransactionManager.current().exec("SELECT SEQUENCE_NAME FROM INFORMATION_SCHEMA.SEQUENCES") { rs ->
while (rs.next()) {
val result = rs.getString("SEQUENCE_NAME")
val sequenceName = if (h2Mode == H2CompatibilityMode.Oracle) {
val q = if (result.contains('.') && !result.isAlreadyQuoted()) "\"" else ""
"$q$result$q"
} else {
result
}
sequences.add(sequenceName)
}
}
return sequences
}

companion object : DialectNameProvider("H2")
}

Original file line number Diff line number Diff line change
@@ -486,18 +486,5 @@ open class OracleDialect : VendorDialect(dialectName, OracleDataTypeProvider, Or
else -> currentDialect.defaultReferenceOption
}

override fun sequences(): List<String> {
val sequences = mutableListOf<String>()
TransactionManager.current().exec("SELECT SEQUENCE_NAME FROM USER_SEQUENCES") { rs ->
while (rs.next()) {
val result = rs.getString("SEQUENCE_NAME")
val q = if (result.contains('.') && !result.isAlreadyQuoted()) "\"" else ""
val sequenceName = "$q$result$q"
sequences.add(sequenceName)
}
}
return sequences
}

companion object : DialectNameProvider("Oracle")
}
Original file line number Diff line number Diff line change
@@ -467,16 +467,6 @@ open class SQLServerDialect : VendorDialect(dialectName, SQLServerDataTypeProvid
// https://docs.microsoft.com/en-us/sql/t-sql/language-elements/like-transact-sql?redirectedfrom=MSDN&view=sql-server-ver15#arguments
override val likePatternSpecialChars = sqlServerLikePatternSpecialChars

override fun sequences(): List<String> {
val sequences = mutableListOf<String>()
TransactionManager.current().exec("SELECT name FROM sys.sequences") { rs ->
while (rs.next()) {
sequences.add(rs.getString("name"))
}
}
return sequences
}

companion object : DialectNameProvider("SQLServer") {
private val sqlServerLikePatternSpecialChars = mapOf('%' to null, '_' to null, '[' to ']')
}
1 change: 1 addition & 0 deletions exposed-jdbc/api/exposed-jdbc.api
Original file line number Diff line number Diff line change
@@ -39,6 +39,7 @@ public final class org/jetbrains/exposed/sql/statements/jdbc/JdbcDatabaseMetadat
public fun existingIndices ([Lorg/jetbrains/exposed/sql/Table;)Ljava/util/Map;
public fun existingPrimaryKeys ([Lorg/jetbrains/exposed/sql/Table;)Ljava/util/Map;
public fun existingSequences ([Lorg/jetbrains/exposed/sql/Table;)Ljava/util/Map;
public fun getDatabaseDialectMode ()Ljava/lang/String;
public fun getDatabaseDialectName ()Ljava/lang/String;
public fun getDatabaseProductVersion ()Ljava/lang/String;
public fun getDefaultIsolationLevel ()I
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.jetbrains.exposed.sql.statements.jdbc

import org.intellij.lang.annotations.Language
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.statements.api.ExposedDatabaseMetadata
import org.jetbrains.exposed.sql.statements.api.IdentifierManagerApi
@@ -47,6 +48,22 @@ class JdbcDatabaseMetadataImpl(database: String, val metadata: DatabaseMetaData)
else -> database
}

override val databaseDialectMode: String? by lazy {
val dialect = currentDialect
if (dialect !is H2Dialect) null

val (settingNameField, settingValueField) = when ((dialect as H2Dialect).majorVersion) {
H2Dialect.H2MajorVersion.One -> "NAME" to "VALUE"
H2Dialect.H2MajorVersion.Two -> "SETTING_NAME" to "SETTING_VALUE"
}

@Language("H2")
val modeQuery = "SELECT $settingValueField FROM INFORMATION_SCHEMA.SETTINGS WHERE $settingNameField = 'MODE'"
TransactionManager.current().exec(modeQuery) { rs ->
rs.iterate { getString(settingValueField) }
}?.firstOrNull()
}

override val databaseProductVersion by lazyMetadata { databaseProductVersion!! }

override val defaultIsolationLevel: Int by lazyMetadata { defaultTransactionIsolation }
@@ -388,12 +405,35 @@ class JdbcDatabaseMetadataImpl(database: String, val metadata: DatabaseMetaData)

@Suppress("MagicNumber")
override fun sequences(): List<String> {
val sequences = mutableListOf<String>()
val rs = metadata.getTables(null, null, null, arrayOf("SEQUENCE"))
while (rs.next()) {
sequences.add(rs.getString(3))
}
return sequences
val dialect = currentDialect
val transaction = TransactionManager.current()
val fieldName = "SEQUENCE_NAME"
return when (dialect) {
is OracleDialect -> transaction.exec("SELECT $fieldName FROM USER_SEQUENCES") { rs ->
rs.iterate {
val seqName = getString(fieldName)
if (identifierManager.isDotPrefixedAndUnquoted(seqName)) "\"$seqName\"" else seqName
}
}
is H2Dialect -> transaction.exec("SELECT $fieldName FROM INFORMATION_SCHEMA.SEQUENCES") { rs ->
rs.iterate {
val seqName = getString(fieldName)
if (dialect.h2Mode == H2CompatibilityMode.Oracle && identifierManager.isDotPrefixedAndUnquoted(seqName)) {
"\"$seqName\""
} else {
seqName
}
}
}
is SQLServerDialect -> transaction.exec("SELECT name AS $fieldName FROM sys.sequences") { rs ->
rs.iterate {
getString(fieldName)
}
}
else -> metadata.getTables(null, null, null, arrayOf("SEQUENCE")).iterate {
getString(3)
}
} ?: emptyList()
}

@Synchronized

0 comments on commit 2633138

Please sign in to comment.