Skip to content

Commit

Permalink
Correct comparison of defaults for String type columns in PostgreSQL (#…
Browse files Browse the repository at this point in the history
…1589)

* Correct comparison of defaults for String type columns in PostgreSQL

* Don't strip single quotes in PostgreSQL

* Exclude MySQL from this test, as it doesn't support default values on text columns.

* Add test for default values that are strings of whitespaces

* Exclude SQLite from test, since it doesn't support changing column default

* Attempt to disable Detekt to see if everything else works
  • Loading branch information
AlexeySoshin committed Nov 14, 2022
1 parent c88153f commit 93033f4
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ object SchemaUtils {
fun createIndex(index: Index) = index.createStatement()

@Suppress("NestedBlockDepth", "ComplexMethod")
private fun DataTypeProvider.dbDefaultToString(exp: Expression<*>): String {
private fun DataTypeProvider.dbDefaultToString(column: Column<*>, exp: Expression<*>): String {
return when (exp) {
is LiteralOp<*> -> when (exp.value) {
is Boolean -> when (currentDialect) {
Expand All @@ -152,12 +152,17 @@ object SchemaUtils {
else -> booleanToStatementString(exp.value)
}
is String -> when (currentDialect) {
is PostgreSQLDialect -> "${exp.value}'::character varying"
is PostgreSQLDialect ->
when(column.columnType) {
is VarCharColumnType -> "'${exp.value}'::character varying"
is TextColumnType -> "'${exp.value}'::text"
else -> processForDefaultValue(exp)
}
else -> exp.value
}
is Enum<*> -> when (exp.columnType) {
is EnumerationNameColumnType<*> -> when (currentDialect) {
is PostgreSQLDialect -> "${exp.value.name}'::character varying"
is PostgreSQLDialect -> "'${exp.value.name}'::character varying"
else -> exp.value.name
}
else -> processForDefaultValue(exp)
Expand Down Expand Up @@ -208,7 +213,7 @@ object SchemaUtils {
val incorrectNullability = existingCol.nullable != columnType.nullable
val incorrectAutoInc = existingCol.autoIncrement != columnType.isAutoInc
val incorrectDefaults =
existingCol.defaultDbValue != col.dbDefaultValue?.let { dataTypeProvider.dbDefaultToString(it) }
existingCol.defaultDbValue != col.dbDefaultValue?.let { dataTypeProvider.dbDefaultToString(col, it) }
val incorrectCaseSensitiveName = existingCol.name.inProperCase() != col.nameInDatabaseCase()
ColumnDiff(incorrectNullability, incorrectAutoInc, incorrectDefaults, incorrectCaseSensitiveName)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ class JdbcDatabaseMetadataImpl(database: String, val metadata: DatabaseMetaData)
dialect is SQLServerDialect -> defaultValue.trim('(', ')', '\'')
dialect is OracleDialect || h2Mode == H2CompatibilityMode.Oracle -> defaultValue.trim().trim('\'')
dialect is MysqlDialect || h2Mode == H2CompatibilityMode.MySQL || h2Mode == H2CompatibilityMode.MariaDB -> defaultValue.substringAfter("b'").trim('\'').trim()
is PostgreSQLDialect -> defaultValue
else -> defaultValue.trim('\'').trim()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,51 @@ class CreateMissingTablesAndColumnsTests : DatabaseTestsBase() {
}
}

@Test
fun `columns with default values that haven't changed shouldn't trigger change`() {
val table = object : Table("varchar_test") {
val varchar = varchar("varchar_column", 255).default("")
val text = text("text_column").default("")
}

// MySQL doesn't support default values on text columns, hence excluded
withDb(excludeSettings = listOf(TestDB.MYSQL)) {
try {
SchemaUtils.create(table)
val actual = SchemaUtils.statementsRequiredToActualizeScheme(table)
assertEqualLists(emptyList(), actual)
} finally {
SchemaUtils.drop(table)
}
}
}

@Test
fun `columns with default values that are whitespaces shouldn't be treated as empty strings`() {
val tableWhitespaceDefault = object : Table("varchar_test") {
val varchar = varchar("varchar_column", 255).default(" ")
val text = text("text_column").default(" ")
}

val tableEmptyStringDefault = object : Table("varchar_test") {
val varchar = varchar("varchar_column", 255).default("")
val text = text("text_column").default("")
}

// MySQL doesn't support default values on text columns, hence excluded
// SQLite doesn't support alter table with add column, so it doesn't generate the statements, hence excluded
withDb(excludeSettings = listOf(TestDB.MYSQL, TestDB.SQLITE)) {
try {
SchemaUtils.create(tableWhitespaceDefault)
val actual = SchemaUtils.statementsRequiredToActualizeScheme(tableEmptyStringDefault)
// Both columns should be considered as changed, since "" != " "
assertEquals(2, actual.size)
} finally {
SchemaUtils.drop(tableEmptyStringDefault, tableWhitespaceDefault)
}
}
}

@Test
fun testAddMissingColumnsStatementsChangeDefault() {
val t1 = object : Table("foo") {
Expand Down

0 comments on commit 93033f4

Please sign in to comment.