Skip to content

Commit

Permalink
Fix implement and test for MySQL version below 5.6
Browse files Browse the repository at this point in the history
Signed-off-by: xJoeWoo <xjoewoo@gmail.com>
  • Loading branch information
xJoeWoo committed Jul 4, 2020
1 parent ba4b75c commit 1cf576b
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal object MysqlDataTypeProvider : DataTypeProvider() {
override fun ulongType(): String = "BIGINT UNSIGNED"

override fun processForDefaultValue(e: Expression<*>): String = when {
e is MysqlDialect.OnUpdateCurrentTimestamp<*> -> QueryBuilder(false).also(e::ddlDefault).toString()
e is MysqlDialect.OnUpdateCurrentTimestamp<*> -> e.ddlDefault()
else -> super.processForDefaultValue(e)
}
}
Expand Down Expand Up @@ -124,15 +124,11 @@ open class MysqlDialect : VendorDialect(dialectName, MysqlDataTypeProvider, Mysq

abstract class OnUpdateCurrentTimestamp<T>(private val currentTimestamp: Expression<T>) : Expression<T>() {

fun ddlDefault(queryBuilder: QueryBuilder) = queryBuilder {
fun ddlDefault():String = QueryBuilder(false).apply {
currentTimestamp.toQueryBuilder(this)
if (TransactionManager.current().db.isVersionCovers(BigDecimal("5.6"))) {
+" ON UPDATE "
currentTimestamp.toQueryBuilder(this)
} else {
exposedLogger.warn("Current MySQL version does not support setting default with `CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP` syntax. Fallback to `CURRENT_TIMESTAMP`.")
}
}
+" ON UPDATE "
currentTimestamp.toQueryBuilder(this)
}.toString()

override fun toQueryBuilder(queryBuilder: QueryBuilder) = currentTimestamp.toQueryBuilder(queryBuilder)
}
Expand All @@ -144,7 +140,8 @@ open class MysqlDialect : VendorDialect(dialectName, MysqlDataTypeProvider, Mysq
override fun isAllowedAsColumnDefault(e: Expression<*>): Boolean {
if (super.isAllowedAsColumnDefault(e)) return true
val acceptableDefaults = setOf("CURRENT_TIMESTAMP", "CURRENT_TIMESTAMP()", "NOW()", "CURRENT_TIMESTAMP(6)", "NOW(6)")
return e.toString().split("ON UPDATE").all { it.trim() in acceptableDefaults } && isFractionDateTimeSupported()
val default = if(e is OnUpdateCurrentTimestamp<*>) e.ddlDefault() else e.toString()
return default.split("ON UPDATE").all { it.trim() in acceptableDefaults } && isFractionDateTimeSupported()
}

override fun fillConstraintCacheForTables(tables: List<Table>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import org.jetbrains.exposed.sql.vendors.MysqlDialect
import org.jetbrains.exposed.sql.vendors.OracleDialect
import org.jetbrains.exposed.sql.vendors.SQLServerDialect
import org.junit.Test
import java.math.BigDecimal
import java.time.*
import kotlin.test.assertNotNull

class DefaultsTest : DatabaseTestsBase() {
object TableWithDBDefault : IntIdTable() {
Expand Down Expand Up @@ -290,37 +292,46 @@ class DefaultsTest : DatabaseTestsBase() {
val name = text("name")
}

val initDateTime = LocalDateTime.now()
withTables(TestDB.values().toList() - TestDB.MYSQL - TestDB.MARIADB, foo) {

val id = fool.insertAndGetId {
it[fool.name] = "bar"
var initDateTime: LocalDateTime = LocalDateTime.MAX
TransactionManager.current().exec("SELECT CURRENT_TIMESTAMP") {
it.next()
initDateTime = it.getTimestamp(1).toLocalDateTime()
}

val id = foo.insertAndGetId {
it[foo.name] = "bar"
}
val result = foo.select { foo.id eq id }.single()

assertEquals("bar", result[foo.name])
val firstAutoUpdateTime = result[foo.defaultDateTimeAutoUpdate]
assert(firstAutoUpdateTime > initDateTime)
val autoUpdateTime = result[foo.defaultDateTimeAutoUpdate]
assertNotNull(autoUpdateTime)
assert(autoUpdateTime >= initDateTime)

if (!db.isVersionCovers(BigDecimal("5.6"))) return@withTables

fool.update({ fool.id eq id }) {
// Using another table without "update time" column to insert
val id2 = fool.insertAndGetId {
it[fool.name] = "baz"
}
val result2 = foo.select { foo.id eq id }.single()
val result2 = foo.select { foo.id eq id2 }.single()

assertEquals("baz", result2[foo.name])
val secondAutoUpdateTime = result2[foo.defaultDateTimeAutoUpdate]
assert(secondAutoUpdateTime > firstAutoUpdateTime)

val autoUpdateTime2 = result2[foo.defaultDateTimeAutoUpdate]
assert(autoUpdateTime2 >= autoUpdateTime)

val id2 = foo.insertAndGetId {
it[foo.name] = "bah"
// And to update
fool.update({ fool.id eq id2 }) {
it[fool.name] = "bah"
}
val result3 = foo.select { foo.id eq id2 }.single()

assertEquals("bah", result3[foo.name])
val thirdAutoUpdateTime = result3[foo.defaultDateTimeAutoUpdate]
assert(thirdAutoUpdateTime > secondAutoUpdateTime)
val autoUpdateTime3 = result3[foo.defaultDateTimeAutoUpdate]
assert(autoUpdateTime3 >= autoUpdateTime2)

}
}

Expand Down

0 comments on commit 1cf576b

Please sign in to comment.