Skip to content

Commit 72d18e5

Browse files
eileencodesrafaelfranca
authored andcommitted
Merge pull request rails#25307 from kamipo/extract_foreign_key_action_from_information_schema
Extract foreign key action from `information_schema`
1 parent aa8f788 commit 72d18e5

File tree

5 files changed

+46
-36
lines changed

5 files changed

+46
-36
lines changed

activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -515,28 +515,30 @@ def foreign_keys(table_name)
515515

516516
schema, name = extract_schema_qualified_name(table_name)
517517

518-
fk_info = select_all <<-SQL.strip_heredoc
519-
SELECT fk.referenced_table_name as 'to_table'
520-
,fk.referenced_column_name as 'primary_key'
521-
,fk.column_name as 'column'
522-
,fk.constraint_name as 'name'
518+
fk_info = select_all(<<-SQL.strip_heredoc, 'SCHEMA')
519+
SELECT fk.referenced_table_name AS 'to_table',
520+
fk.referenced_column_name AS 'primary_key',
521+
fk.column_name AS 'column',
522+
fk.constraint_name AS 'name',
523+
rc.update_rule AS 'on_update',
524+
rc.delete_rule AS 'on_delete'
523525
FROM information_schema.key_column_usage fk
524-
WHERE fk.referenced_column_name is not null
526+
JOIN information_schema.referential_constraints rc
527+
USING (constraint_schema, constraint_name)
528+
WHERE fk.referenced_column_name IS NOT NULL
525529
AND fk.table_schema = #{quote(schema)}
526530
AND fk.table_name = #{quote(name)}
527531
SQL
528532

529-
create_table_info = create_table_info(table_name)
530-
531533
fk_info.map do |row|
532534
options = {
533535
column: row['column'],
534536
name: row['name'],
535537
primary_key: row['primary_key']
536538
}
537539

538-
options[:on_update] = extract_foreign_key_action(create_table_info, row['name'], "UPDATE")
539-
options[:on_delete] = extract_foreign_key_action(create_table_info, row['name'], "DELETE")
540+
options[:on_update] = extract_foreign_key_action(row['on_update'])
541+
options[:on_delete] = extract_foreign_key_action(row['on_delete'])
540542

541543
ForeignKeyDefinition.new(table_name, row['to_table'], options)
542544
end
@@ -883,12 +885,10 @@ def column_definitions(table_name) # :nodoc:
883885
end
884886
end
885887

886-
def extract_foreign_key_action(structure, name, action) # :nodoc:
887-
if structure =~ /CONSTRAINT #{quote_column_name(name)} FOREIGN KEY .* REFERENCES .* ON #{action} (CASCADE|SET NULL|RESTRICT)/
888-
case $1
889-
when 'CASCADE'; :cascade
890-
when 'SET NULL'; :nullify
891-
end
888+
def extract_foreign_key_action(specifier) # :nodoc:
889+
case specifier
890+
when 'CASCADE'; :cascade
891+
when 'SET NULL'; :nullify
892892
end
893893
end
894894

activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ def rename_index(table_name, old_name, new_name)
579579
end
580580

581581
def foreign_keys(table_name)
582-
fk_info = select_all <<-SQL.strip_heredoc
582+
fk_info = select_all(<<-SQL.strip_heredoc, 'SCHEMA')
583583
SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
584584
FROM pg_constraint c
585585
JOIN pg_class t1 ON c.conrelid = t1.oid

activerecord/test/cases/adapters/mysql2/schema_test.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,24 @@ def test_drop_temporary_table
103103
end
104104
end
105105
end
106+
107+
class Mysql2AnsiQuotesTest < ActiveRecord::Mysql2TestCase
108+
def setup
109+
@connection = ActiveRecord::Base.connection
110+
@connection.execute("SET SESSION sql_mode='ANSI_QUOTES'")
111+
end
112+
113+
def teardown
114+
@connection.reconnect!
115+
end
116+
117+
def test_primary_key_method_with_ansi_quotes
118+
assert_equal "id", @connection.primary_key("topics")
119+
end
120+
121+
def test_foreign_keys_method_with_ansi_quotes
122+
fks = @connection.foreign_keys("lessons_students")
123+
assert_equal([["lessons_students", "students", :cascade]],
124+
fks.map {|fk| [fk.from_table, fk.to_table, fk.on_delete] })
125+
end
126+
end

activerecord/test/cases/primary_keys_test.rb

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -275,18 +275,6 @@ def test_collectly_dump_composite_primary_key
275275
end
276276

277277
if current_adapter?(:Mysql2Adapter)
278-
class PrimaryKeyWithAnsiQuotesTest < ActiveRecord::TestCase
279-
self.use_transactional_tests = false
280-
281-
def test_primary_key_method_with_ansi_quotes
282-
con = ActiveRecord::Base.connection
283-
con.execute("SET SESSION sql_mode='ANSI_QUOTES'")
284-
assert_equal "id", con.primary_key("topics")
285-
ensure
286-
con.reconnect!
287-
end
288-
end
289-
290278
class PrimaryKeyBigintNilDefaultTest < ActiveRecord::TestCase
291279
include SchemaDumpingHelper
292280

activerecord/test/schema/schema.rb

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,14 @@
409409
t.references :student
410410
end
411411

412+
create_table :students, force: true do |t|
413+
t.string :name
414+
t.boolean :active
415+
t.integer :college_id
416+
end
417+
418+
add_foreign_key :lessons_students, :students, on_delete: :cascade
419+
412420
create_table :lint_models, force: true
413421

414422
create_table :line_items, force: true do |t|
@@ -777,12 +785,6 @@
777785
t.integer :lock_version, null: false, default: 0
778786
end
779787

780-
create_table :students, force: true do |t|
781-
t.string :name
782-
t.boolean :active
783-
t.integer :college_id
784-
end
785-
786788
create_table :subscribers, force: true, id: false do |t|
787789
t.string :nick, null: false
788790
t.string :name
@@ -1002,7 +1004,6 @@
10021004
end
10031005

10041006
add_foreign_key :fk_test_has_fk, :fk_test_has_pk, column: "fk_id", name: "fk_name", primary_key: "pk_id"
1005-
add_foreign_key :lessons_students, :students
10061007
end
10071008

10081009
create_table :overloaded_types, force: true do |t|

0 commit comments

Comments
 (0)