diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/Default.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/Default.kt index 1574c63610..509b31335c 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/Default.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/Default.kt @@ -95,6 +95,7 @@ abstract class DataTypeProvider { open fun processForDefaultValue(e: Expression<*>): String = when { e is LiteralOp<*> -> "$e" currentDialect is MysqlDialect -> "$e" + currentDialect is SQLServerDialect -> "$e" else -> "($e)" } } diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/SQLServerDialect.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/SQLServerDialect.kt index 0f2b6d00a4..c608a9fbab 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/SQLServerDialect.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/vendors/SQLServerDialect.kt @@ -149,7 +149,12 @@ open class SQLServerDialect : VendorDialect(dialectName, SQLServerDataTypeProvid override val supportsSequenceAsGeneratedKeys: Boolean = false override val supportsOnlyIdentifiersInGeneratedKeys: Boolean = true - override fun isAllowedAsColumnDefault(e: Expression<*>): Boolean = true + private val nonAcceptableDefaults = arrayOf("DEFAULT") + + override fun isAllowedAsColumnDefault(e: Expression<*>): Boolean { + val columnDefault = e.toString().toUpperCase().trim() + return columnDefault !in nonAcceptableDefaults + } override fun modifyColumn(column: Column<*>): String = super.modifyColumn(column).replace("MODIFY COLUMN", "ALTER COLUMN") diff --git a/exposed-java-time/src/test/kotlin/org/jetbrains/exposed/DefaultsTest.kt b/exposed-java-time/src/test/kotlin/org/jetbrains/exposed/DefaultsTest.kt index 159223dd89..2fafab0dfe 100644 --- a/exposed-java-time/src/test/kotlin/org/jetbrains/exposed/DefaultsTest.kt +++ b/exposed-java-time/src/test/kotlin/org/jetbrains/exposed/DefaultsTest.kt @@ -1,10 +1,14 @@ package org.jetbrains.exposed +import org.hamcrest.CoreMatchers.`is` +import org.hamcrest.CoreMatchers.notNullValue +import org.hamcrest.MatcherAssert.assertThat import org.jetbrains.exposed.dao.IntEntity import org.jetbrains.exposed.dao.IntEntityClass import org.jetbrains.exposed.dao.flushCache import org.jetbrains.exposed.dao.id.EntityID import org.jetbrains.exposed.dao.id.IntIdTable +import org.jetbrains.exposed.dao.id.UUIDTable import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.`java-time`.* import org.jetbrains.exposed.sql.statements.BatchDataInconsistentException @@ -17,12 +21,12 @@ import org.jetbrains.exposed.sql.tests.shared.assertEqualCollections import org.jetbrains.exposed.sql.tests.shared.assertEqualLists import org.jetbrains.exposed.sql.tests.shared.assertEquals import org.jetbrains.exposed.sql.tests.shared.expectException -import org.jetbrains.exposed.sql.transactions.TransactionManager 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.time.* +import java.util.UUID class DefaultsTest : DatabaseTestsBase() { object TableWithDBDefault : IntIdTable() { @@ -294,4 +298,47 @@ class DefaultsTest : DatabaseTestsBase() { assertEquals(1, count) } } + + @Test + fun testDefaultExpressionsForTemporalTable() { + + fun databaseGeneratedTimestamp() = object : ExpressionWithColumnType() { + override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder { +"DEFAULT" } + override val columnType: IColumnType = JavaLocalDateTimeColumnType() + } + + val temporalTable = object : UUIDTable("TemporalTable") { + val name = text("name") + val sysStart = datetime("sysStart").defaultExpression(databaseGeneratedTimestamp()) + val sysEnd = datetime("sysEnd").defaultExpression(databaseGeneratedTimestamp()) + } + + withDb(TestDB.SQLSERVER) { + try { + exec(""" + CREATE TABLE TemporalTable + ( + id uniqueidentifier PRIMARY KEY, + "name" VARCHAR(100) NOT NULL, + sysStart DATETIME2 GENERATED ALWAYS AS ROW START, + sysEnd DATETIME2 GENERATED ALWAYS AS ROW END, + PERIOD FOR SYSTEM_TIME ([sysStart], [sysEnd]) + ) + """.trimIndent()) + + val names = listOf("name") + val batchInsert: List = + temporalTable.batchInsert(names, shouldReturnGeneratedValues = true) { name -> + this[temporalTable.name] = "name" + } + val id = batchInsert.first()[temporalTable.id] + val result = temporalTable.select { temporalTable.id eq id }.single() + assertThat(result[temporalTable.name], `is`("name")) + assertThat(result[temporalTable.sysStart], notNullValue()) + assertThat(result[temporalTable.sysEnd], notNullValue()) + } finally { + SchemaUtils.drop(temporalTable) + } + } + } }