activerecord-jdbc-adapter
activerecord-jdbc-adapter copied to clipboard
Renaming a table does not rename indexes in Rails 4
I'm trying to upgrade the JRuby version of my Rails 4 application from 9.1.2.0 to 9.2.5.0 but faced an issue with migrations.
When a rename_table
is used it does not issue an ALTER INDEX
properly.
Here is a reproduction script I created: https://gist.github.com/nbekirov/88e4a9ebcc066193141f11f865bd1490
When executed under jruby 9.1.7.0 (2.3.1) it yields:
-- table_exists?(:global_suppliers)
D, [2019-01-29T17:23:21.919000 #21875] DEBUG -- : (33.0ms) SELECT version()
-> 0.3560s
-- create_table(:suppliers, {:force=>true})
D, [2019-01-29T17:23:22.173000 #21875] DEBUG -- : (87.0ms) CREATE TABLE "suppliers" ("id" serial primary key, "name" character varying)
-> 0.0974s
-> 0 rows
-- add_index(:suppliers, :name)
D, [2019-01-29T17:23:22.193000 #21875] DEBUG -- : (7.0ms) CREATE INDEX "index_suppliers_on_name" ON "suppliers" ("name")
-> 0.0205s
-> 0 rows
Run options: --seed 39800
# Running:
== RenameSuppliersToMegaSuppliers: migrating =================================
-- rename_table(:suppliers, :global_suppliers)
D, [2019-01-29T17:23:22.259000 #21875] DEBUG -- : (4.0ms) ALTER TABLE "suppliers" RENAME TO "global_suppliers"
D, [2019-01-29T17:23:22.297000 #21875] DEBUG -- : PK and Serial Sequence (35.0ms) SELECT attr.attname, seq.relname
FROM pg_class seq,
pg_attribute attr,
pg_depend dep,
pg_constraint cons
WHERE seq.oid = dep.objid
AND seq.relkind = 'S'
AND attr.attrelid = dep.refobjid
AND attr.attnum = dep.refobjsubid
AND attr.attrelid = cons.conrelid
AND attr.attnum = cons.conkey[1]
AND cons.contype = 'p'
AND dep.refobjid = '"global_suppliers"'::regclass
D, [2019-01-29T17:23:22.302000 #21875] DEBUG -- : (5.0ms) ALTER TABLE "suppliers_id_seq" RENAME TO "global_suppliers_id_seq"
D, [2019-01-29T17:23:22.314000 #21875] DEBUG -- : (9.0ms) ALTER INDEX "suppliers_pkey" RENAME TO "global_suppliers_pkey"
-> 0.0625s
== RenameSuppliersToMegaSuppliers: migrated (0.0644s) ========================
F
Finished in 0.191794s, 5.2139 runs/s, 5.2139 assertions/s.
1) Failure:
BugTest#test_migration_up [table_rename.rb:51]:
--- expected
+++ actual
@@ -1 +1 @@
-["index_global_suppliers_on_name"]
+["index_suppliers_on_name"]
1 runs, 1 assertions, 1 failures, 0 errors, 0 skips
Compare that to the result of the same script executed under jruby 9.1.6.0 (2.3.1):
-- table_exists?(:global_suppliers)
D, [2019-01-29T17:25:59.209000 #21958] DEBUG -- : (22.0ms) SELECT version()
-> 0.2370s
-- drop_table(:global_suppliers)
D, [2019-01-29T17:25:59.336000 #21958] DEBUG -- : (38.0ms) DROP TABLE "global_suppliers"
-> 0.0386s
-> 0 rows
-- create_table(:suppliers, {:force=>true})
D, [2019-01-29T17:25:59.396000 #21958] DEBUG -- : (46.0ms) CREATE TABLE "suppliers" ("id" serial primary key, "name" character varying)
-> 0.0591s
-> 0 rows
-- add_index(:suppliers, :name)
D, [2019-01-29T17:25:59.433000 #21958] DEBUG -- : (19.0ms) CREATE INDEX "index_suppliers_on_name" ON "suppliers" ("name")
-> 0.0373s
-> 0 rows
Run options: --seed 54298
# Running:
== RenameSuppliersToMegaSuppliers: migrating =================================
-- rename_table(:suppliers, :global_suppliers)
D, [2019-01-29T17:25:59.483000 #21958] DEBUG -- : (3.0ms) ALTER TABLE "suppliers" RENAME TO "global_suppliers"
D, [2019-01-29T17:25:59.526000 #21958] DEBUG -- : PK and Serial Sequence (41.0ms) SELECT attr.attname, seq.relname
FROM pg_class seq,
pg_attribute attr,
pg_depend dep,
pg_constraint cons
WHERE seq.oid = dep.objid
AND seq.relkind = 'S'
AND attr.attrelid = dep.refobjid
AND attr.attnum = dep.refobjsubid
AND attr.attrelid = cons.conrelid
AND attr.attnum = cons.conkey[1]
AND cons.contype = 'p'
AND dep.refobjid = '"global_suppliers"'::regclass
D, [2019-01-29T17:25:59.534000 #21958] DEBUG -- : (6.0ms) ALTER TABLE "suppliers_id_seq" RENAME TO "global_suppliers_id_seq"
D, [2019-01-29T17:25:59.538000 #21958] DEBUG -- : (2.0ms) ALTER INDEX "suppliers_pkey" RENAME TO "global_suppliers_pkey"
D, [2019-01-29T17:25:59.585000 #21958] DEBUG -- : (2.0ms) ALTER INDEX "index_suppliers_on_name" RENAME TO "index_global_suppliers_on_name"
-> 0.1061s
== RenameSuppliersToMegaSuppliers: migrated (0.1065s) ========================
.
Finished in 0.134313s, 7.4453 runs/s, 7.4453 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
What I found while trying to debug the situation:
-
ArJdbc::PostgreSQL#rename_table
is trying to callActiveRecord::ConnectionAdapters::SchemaStatements#rename_table_indexes
(source) - only if it
respond_to?(:rename_table_indexes)
(same source, change commit) - but
#rename_table_indexes
is a protected method (source) - and jruby 9.1.7.0
respond_to?
private/protected bahaviour changed (news article, bug, commit) - which prevents the invocation of
#rename_table_indexes
Related StackOverflow issue: https://stackoverflow.com/questions/48925738/rails-4-renaming-column-with-index
please could you also fill in your AR-JDBC gem and Rails 4.x version - might come handy for reproducing
@kares, my bad - assumed that listing those only in the reproduction script is enough.
My original application setup is:
- rails: 4.2.7.1 (want to upgrade to 4.2.11)
- activerecord-jdbcpostgresql-adapter: 1.3.23 (want to upgrade to 1.3.25)
- jruby: 9.1.2.0 (want to upgrade first to 9.1.17.0 then to 9.2.5.0)
In the provided reproduction script I've used:
- activerecord: 4.2.11 (definned in gemfile block)
- activerecord-jdbcpostgresql-adapter: 1.3.25 (definned in gemfile block)
- jruby: 9.1.6.0/9.1.7.0 (instruction in comment)
thanks, sorry I haven't looked at the script first - assumed it to be the same as you initially posted on IRC. ... still one thing that isn't clear - how is 9.2.5.0 doing in terms of reproduction for you, is it working fine ? (since this seems like a JRuby bug yet 9.1 likely won't get another release)
With my 9.2.5.0 it is failing.
$ ruby -v
jruby 9.2.5.0 (2.5.0) 2018-12-06 6d5a228 Java HotSpot(TM) 64-Bit Server VM 9.0.1+11 on 9.0.1+11 +jit [darwin-x86_64]
My idea is that the change of how jruby behaves when evaluting respond_to?
is what prevents the proper index renaming. It's not 9.1.7.0 and later versions being buggy and needing a fix, but precisely the oposite - previous versions where doing the wrong thing. Check out this sample ruby script:
class Dog
def can_bark?
respond_to?(:do_bark)
end
def bark
do_bark
end
protected
def do_bark
'woof! '
end
end
dog = Dog.new
call | jruby-9.1.6.0 | jruby-9.2.5.0 | ruby-2.4.5 and other 2.x |
---|---|---|---|
dog.can_bark? | true | false | false |
dog.bark | woof! | woof! | woof! |
dog.do_bark | protected method `do_bark' called for #Dog:.. | -same- | -same- |
Extended description and examples can be found in this article: https://tenderlovemaking.com/2012/09/07/protected-methods-and-ruby-2-0.html
Just in case anyone needs a fast and dirty workaround, here's a monkey-patch I came up with:
module ArJdbc
module PostgreSQL
def respond_to_missing?(method_name, _include_private = false)
# Allow proper index management in jruby-9.1.7.0+
# See: https://github.com/jruby/activerecord-jdbc-adapter/issues/985
[
:rename_table_indexes,
:rename_column_indexes,
:validate_index_length!
].include?(method_name.to_sym) || super
end
end
end