pg_ha_migrations 2.2.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +1 -3
- data/Appraisals +4 -0
- data/README.md +18 -4
- data/gemfiles/rails_8.1.gemfile +7 -0
- data/lib/pg_ha_migrations/allowed_versions.rb +1 -1
- data/lib/pg_ha_migrations/safe_statements.rb +25 -0
- data/lib/pg_ha_migrations/version.rb +1 -1
- data/pg_ha_migrations.gemspec +2 -2
- metadata +9 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2092871922f1fb41ad0d82a1cda3b1b8ad57bf03b9e9a324d452110926754dba
|
|
4
|
+
data.tar.gz: 9e1e74c22f51cdf6d36333fdd6740ebdd5d5d4e76053a000859e7027b39ac9e5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 88089a7139e0ec580ff9c32574b4fd890d7bf7203740e6d3ec4821a6d03aed728868602de5347b441a2607951234b157cd19485710591b37e27dda803f4f46c7
|
|
7
|
+
data.tar.gz: a52081ab69232926e4484ac0d551437f61b719e0d1514cba507dcbcaf97c363726f2729037170e452f7d7d153847601604f50f92a837a374afc854e0d37f46d1
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -5,7 +5,6 @@ jobs:
|
|
|
5
5
|
strategy:
|
|
6
6
|
matrix:
|
|
7
7
|
pg:
|
|
8
|
-
- 13
|
|
9
8
|
- 14
|
|
10
9
|
- 15
|
|
11
10
|
- 16
|
|
@@ -19,12 +18,11 @@ jobs:
|
|
|
19
18
|
- rails_7.1
|
|
20
19
|
- rails_7.2
|
|
21
20
|
- rails_8.0
|
|
21
|
+
- rails_8.1
|
|
22
22
|
partman:
|
|
23
23
|
- 4
|
|
24
24
|
- 5
|
|
25
25
|
exclude:
|
|
26
|
-
- pg: 13
|
|
27
|
-
partman: 5 # Partman 5.x is not available in PGDG for PG 13
|
|
28
26
|
- pg: 17
|
|
29
27
|
partman: 4 # Partman 4.x is not available in PGDG for PG 17
|
|
30
28
|
- pg: 18
|
data/Appraisals
CHANGED
data/README.md
CHANGED
|
@@ -63,9 +63,21 @@ We believe the `force: true` option to ActiveRecord's `create_table` method is a
|
|
|
63
63
|
|
|
64
64
|
### Rollback
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
Although some schema changes are safe to reverse (e.g., dropping a just-created non-unique index), most possible schema changes are not safe to reverse. A few examples relative to database integrity:
|
|
67
|
+
* Dropping a newly added column may result in data loss.
|
|
68
|
+
* Re-adding a dropped unique index (or any other constraint) may fail because data may now exist that violates the constraint.
|
|
69
|
+
* Dropping a enum value simply isn’t supported by Postgres (and wouldn’t be safe since it might be referenced by rows in the database).
|
|
67
70
|
|
|
68
|
-
|
|
71
|
+
These concerns are magnified if we also consider currently running application code (especially across multiple revisions, i.e., during a deploy). For example, the application may expect:
|
|
72
|
+
* Indexes to be present for performant queries.
|
|
73
|
+
* Constraints to hold.
|
|
74
|
+
* Columns to be present.
|
|
75
|
+
|
|
76
|
+
Therefore we require that ["Rollback strategies do not involve reverting the database schema to its previous version"](https://medium.com/paypal-tech/postgresql-at-scale-database-schema-changes-without-downtime-20d3749ed680#360a), and PgHaMigrations does not support ActiveRecord's automatic migration rollback capability.
|
|
77
|
+
|
|
78
|
+
Instead we concentrate on ensuring that operations are safe to apply while both old and new revisions of an application are running. In the rare case where we need to “undo” a schema change, we roll forward, rather than rolling back, by having an engineer write a new schema change and deploying that change.
|
|
79
|
+
|
|
80
|
+
We write all of our migrations with only an `def up` method like:
|
|
69
81
|
|
|
70
82
|
```
|
|
71
83
|
def up
|
|
@@ -73,7 +85,9 @@ def up
|
|
|
73
85
|
end
|
|
74
86
|
```
|
|
75
87
|
|
|
76
|
-
and never use `def change`.
|
|
88
|
+
and never use `def change`.
|
|
89
|
+
|
|
90
|
+
For development environments we iterate by recreating the database from scratch every time we make a change.
|
|
77
91
|
|
|
78
92
|
### Transactional DDL
|
|
79
93
|
|
|
@@ -102,7 +116,7 @@ The following functionality is currently unsupported:
|
|
|
102
116
|
|
|
103
117
|
### Compatibility Notes
|
|
104
118
|
|
|
105
|
-
- While some features may work with other versions, this gem is currently tested against PostgreSQL
|
|
119
|
+
- While some features may work with other versions, this gem is currently tested against PostgreSQL 14+ and Partman 4+
|
|
106
120
|
|
|
107
121
|
### Migration Methods
|
|
108
122
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require "active_record/migration/compatibility"
|
|
2
2
|
|
|
3
3
|
module PgHaMigrations::AllowedVersions
|
|
4
|
-
ALLOWED_VERSIONS = [4.2, 5.0, 5.1, 5.2, 6.0, 6.1, 7.0, 7.1, 7.2, 8.0].map do |v|
|
|
4
|
+
ALLOWED_VERSIONS = [4.2, 5.0, 5.1, 5.2, 6.0, 6.1, 7.0, 7.1, 7.2, 8.0, 8.1].map do |v|
|
|
5
5
|
begin
|
|
6
6
|
ActiveRecord::Migration[v]
|
|
7
7
|
rescue ArgumentError
|
|
@@ -326,6 +326,31 @@ module PgHaMigrations::SafeStatements
|
|
|
326
326
|
PgHaMigrations::Index.from_table_and_columns(child_table, columns)
|
|
327
327
|
end
|
|
328
328
|
|
|
329
|
+
# A previous run that was interrupted mid-build can leave an invalid index
|
|
330
|
+
# behind on a child partition. Because CREATE INDEX ... IF NOT EXISTS matches
|
|
331
|
+
# on name only (not validity), that leftover would be skipped and never
|
|
332
|
+
# rebuilt, so the parent index would never become valid and this method
|
|
333
|
+
# would raise below on every re-run. When resuming (if_not_exists), drop any
|
|
334
|
+
# invalid child leftovers first so they get rebuilt. They are unattached at
|
|
335
|
+
# this point (the attach step runs only after every child index is built),
|
|
336
|
+
# so they can be dropped concurrently.
|
|
337
|
+
if if_not_exists && child_indexes.present?
|
|
338
|
+
quoted_child_index_names = child_indexes.map { |child_index| connection.quote(child_index.name) }.join(", ")
|
|
339
|
+
|
|
340
|
+
invalid_child_index_names = connection.select_values(<<~SQL)
|
|
341
|
+
SELECT pg_class.relname
|
|
342
|
+
FROM pg_index
|
|
343
|
+
JOIN pg_class ON pg_class.oid = pg_index.indexrelid
|
|
344
|
+
WHERE NOT pg_index.indisvalid
|
|
345
|
+
AND pg_class.relkind = 'i'
|
|
346
|
+
AND pg_class.relname = ANY (ARRAY[#{quoted_child_index_names}])
|
|
347
|
+
SQL
|
|
348
|
+
|
|
349
|
+
child_indexes.select { |index| invalid_child_index_names.include?(index.name) }.each do |child_index|
|
|
350
|
+
safe_remove_concurrent_index(child_index.table.fully_qualified_name, name: child_index.name)
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
329
354
|
# CREATE INDEX ON ONLY parent_table
|
|
330
355
|
unsafe_add_index(
|
|
331
356
|
parent_table.fully_qualified_name,
|
data/pg_ha_migrations.gemspec
CHANGED
|
@@ -37,7 +37,7 @@ Gem::Specification.new do |spec|
|
|
|
37
37
|
spec.add_development_dependency "pry-byebug"
|
|
38
38
|
spec.add_development_dependency "appraisal", "~> 2.5"
|
|
39
39
|
|
|
40
|
-
spec.add_dependency "rails", ">= 7.1", "< 8.
|
|
41
|
-
spec.add_dependency "relation_to_struct", "
|
|
40
|
+
spec.add_dependency "rails", ">= 7.1", "< 8.2"
|
|
41
|
+
spec.add_dependency "relation_to_struct", "~> 1.9"
|
|
42
42
|
spec.add_dependency "ruby2_keywords"
|
|
43
43
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pg_ha_migrations
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- celeen
|
|
@@ -13,7 +13,7 @@ authors:
|
|
|
13
13
|
- redneckbeard
|
|
14
14
|
bindir: exe
|
|
15
15
|
cert_chain: []
|
|
16
|
-
date: 2026-
|
|
16
|
+
date: 2026-07-31 00:00:00.000000000 Z
|
|
17
17
|
dependencies:
|
|
18
18
|
- !ruby/object:Gem::Dependency
|
|
19
19
|
name: rake
|
|
@@ -122,7 +122,7 @@ dependencies:
|
|
|
122
122
|
version: '7.1'
|
|
123
123
|
- - "<"
|
|
124
124
|
- !ruby/object:Gem::Version
|
|
125
|
-
version: '8.
|
|
125
|
+
version: '8.2'
|
|
126
126
|
type: :runtime
|
|
127
127
|
prerelease: false
|
|
128
128
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -132,21 +132,21 @@ dependencies:
|
|
|
132
132
|
version: '7.1'
|
|
133
133
|
- - "<"
|
|
134
134
|
- !ruby/object:Gem::Version
|
|
135
|
-
version: '8.
|
|
135
|
+
version: '8.2'
|
|
136
136
|
- !ruby/object:Gem::Dependency
|
|
137
137
|
name: relation_to_struct
|
|
138
138
|
requirement: !ruby/object:Gem::Requirement
|
|
139
139
|
requirements:
|
|
140
|
-
- - "
|
|
140
|
+
- - "~>"
|
|
141
141
|
- !ruby/object:Gem::Version
|
|
142
|
-
version: 1.
|
|
142
|
+
version: '1.9'
|
|
143
143
|
type: :runtime
|
|
144
144
|
prerelease: false
|
|
145
145
|
version_requirements: !ruby/object:Gem::Requirement
|
|
146
146
|
requirements:
|
|
147
|
-
- - "
|
|
147
|
+
- - "~>"
|
|
148
148
|
- !ruby/object:Gem::Version
|
|
149
|
-
version: 1.
|
|
149
|
+
version: '1.9'
|
|
150
150
|
- !ruby/object:Gem::Dependency
|
|
151
151
|
name: ruby2_keywords
|
|
152
152
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -188,6 +188,7 @@ files:
|
|
|
188
188
|
- gemfiles/rails_7.1.gemfile
|
|
189
189
|
- gemfiles/rails_7.2.gemfile
|
|
190
190
|
- gemfiles/rails_8.0.gemfile
|
|
191
|
+
- gemfiles/rails_8.1.gemfile
|
|
191
192
|
- lib/pg_ha_migrations.rb
|
|
192
193
|
- lib/pg_ha_migrations/allowed_versions.rb
|
|
193
194
|
- lib/pg_ha_migrations/blocking_database_transactions.rb
|