Skip to content

Commit

Permalink
fix!: EXPOSED-691 [PostgreSQL] Restrict dropping unmapped sequences t…
Browse files Browse the repository at this point in the history
…o related tables only

- Update KDocs & Breaking changes doc
  • Loading branch information
bog-walk committed Jan 16, 2025
1 parent b04dc12 commit 18198e5
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 7 deletions.
6 changes: 6 additions & 0 deletions documentation-website/Writerside/topics/Breaking-Changes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Breaking Changes

## 0.59.0
* [PostgreSQL] `MigrationUtils.statementsRequiredForDatabaseMigration(*tables)` used to potentially return `DROP` statements for any database sequence not
mapped to an Exposed table object. Now it only checks against database sequences that have a relational dependency on any of the specified tables
(for example, any sequence automatically associated with a `SERIAL` column registered to `IdTable`). An unbound sequence created manually
via the `CREATE SEQUENCE` command will no longer be checked and will not generate a `DROP` statement.

## 0.57.0
* Insert, Upsert, and Replace statements will no longer implicitly send all default values (except for client-side default values) in every SQL request.
This change will reduce the amount of data Exposed sends to the database and make Exposed rely more on the database's default values.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Sequence(
val identifier
get() = TransactionManager.current().db.identifierManager.cutIfNecessaryAndQuote(name)

override fun toString(): String = identifier
override fun toString(): String = "Sequence(identifier=$identifier)"

/** The SQL statements that create this sequence. */
val ddl: List<String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ abstract class ExposedDatabaseMetadata(val database: String) {
* Returns a map with all the defined sequences that hold a relation to the specified [tables] in the database.
*
* **Note** PostgreSQL is currently the only database that maps relational dependencies for sequences created when
* a SERIAL column is registered to a table. Any sequence created using the CREATE SEQUENCE command will be ignored
* a SERIAL column is registered to an `IdTable`. Using this method with any other database returns an empty map.
*
* Any sequence created using the CREATE SEQUENCE command will be ignored
* as it is not necessarily bound to any particular table. Sequences that are used in a table via triggers will also
* not be returned.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ interface DatabaseDialect {
* Returns a map with all the defined sequences that hold a relation to the specified [tables] in the database.
*
* **Note** PostgreSQL is currently the only database that maps relational dependencies for sequences created when
* a SERIAL column is registered to a table. Any sequence created using the CREATE SEQUENCE command will be ignored
* a SERIAL column is registered to an `IdTable`. Using this method with any other database returns an empty map.
*
* Any sequence created using the CREATE SEQUENCE command will be ignored
* as it is not necessarily bound to any particular table. Sequences that are used in a table via triggers will also
* not be returned.
*/
Expand Down
24 changes: 20 additions & 4 deletions exposed-migration/src/main/kotlin/MigrationUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import org.jetbrains.exposed.sql.SchemaUtils.checkExcessiveForeignKeyConstraints
import org.jetbrains.exposed.sql.SchemaUtils.checkExcessiveIndices
import org.jetbrains.exposed.sql.SchemaUtils.checkMappingConsistence
import org.jetbrains.exposed.sql.SchemaUtils.createStatements
import org.jetbrains.exposed.sql.SchemaUtils.statementsRequiredToActualizeScheme
import org.jetbrains.exposed.sql.Sequence
import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.sql.exists
Expand Down Expand Up @@ -59,14 +58,22 @@ object MigrationUtils {

/**
* Returns the SQL statements that need to be executed to make the existing database schema compatible with
* the table objects defined using Exposed. Unlike [statementsRequiredToActualizeScheme], DROP/DELETE statements are
* included.
* the table objects defined using Exposed. Unlike `SchemaUtils.statementsRequiredToActualizeScheme()`,
* DROP/DELETE statements are included.
*
* **Note:** Some databases, like **SQLite**, only support `ALTER TABLE ADD COLUMN` syntax in very restricted cases,
* which may cause unexpected behavior when adding some missing columns. For more information,
* refer to the relevant documentation.
* For SQLite, see [ALTER TABLE restrictions](https://www.sqlite.org/lang_altertable.html#alter_table_add_column).
*
* **Note:** If this method is called on a **PostgreSQL** database, it will check for a mapping inconsistency
* between the specified [tables] and existing sequences that have a relational dependency on any of these [tables]
* (for example, any sequence automatically associated with a `SERIAL` column registered to `IdTable`). This means
* that an unbound sequence created manually via the `CREATE SEQUENCE` command will no longer be checked and will
* not generate a DROP statement.
* When called on other databases, such an inconsistency will be checked against all sequences from the database,
* potentially returning DROP statements for any sequence unlinked or unrelated to [tables].
*
* By default, a description for each intermediate step, as well as its execution time, is logged at the INFO level.
* This can be disabled by setting [withLogs] to `false`.
*/
Expand Down Expand Up @@ -140,7 +147,12 @@ object MigrationUtils {

/**
* Log Exposed table mappings <-> real database mapping problems and returns DDL Statements to fix them, including
* DROP/DELETE statements (unlike [checkMappingConsistence])
* DROP/DELETE statements (unlike [checkMappingConsistence]).
*
* **Note:** If this method is called on a PostgreSQL database, only sequences with a relational dependency on any
* of the specified [tables] will be checked for a mapping inconsistency. When called on other databases, all sequences
* from the database will be checked, potentially returning SQL statements to drop any sequences that are unlinked
* or unrelated to [tables].
*/
private fun mappingConsistenceRequiredStatements(vararg tables: Table, withLogs: Boolean = true): List<String> {
return checkMissingIndices(tables = tables, withLogs).flatMap { it.createStatement() } +
Expand Down Expand Up @@ -305,6 +317,10 @@ object MigrationUtils {
* Checks all [tables] for any that have sequences that exist in the database but are not mapped in the code. If
* found, this function also logs the SQL statements that can be used to drop these sequences.
*
* **Note:** If this method is called on a PostgreSQL database, only sequences with a relational dependency on any
* of the specified [tables] will be checked for a mapping in Exposed code. When called on other databases, all sequences
* from the database will be checked, potentially returning any [Sequence] unlinked or unrelated to [tables].
*
* @return List of sequences that are unmapped and can be dropped.
*/
private fun checkUnmappedSequences(vararg tables: Table, withLogs: Boolean): List<Sequence> {
Expand Down

0 comments on commit 18198e5

Please sign in to comment.