Skip to content

Commit 6af9cba

Browse files
authored
Merge pull request rails#47353 from fatkodima/pg-foreign-keys-reserved-words
Fix retrieving foreign keys referencing tables named like keywords in PostgreSQL and MySQL
2 parents 6cea258 + 73fcc18 commit 6af9cba

File tree

5 files changed

+32
-14
lines changed

5 files changed

+32
-14
lines changed

activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -491,15 +491,15 @@ def foreign_keys(table_name)
491491

492492
fk_info.map do |row|
493493
options = {
494-
column: row["column"],
494+
column: unquote_identifier(row["column"]),
495495
name: row["name"],
496496
primary_key: row["primary_key"]
497497
}
498498

499499
options[:on_update] = extract_foreign_key_action(row["on_update"])
500500
options[:on_delete] = extract_foreign_key_action(row["on_delete"])
501501

502-
ForeignKeyDefinition.new(table_name, row["to_table"], options)
502+
ForeignKeyDefinition.new(table_name, unquote_identifier(row["to_table"]), options)
503503
end
504504
end
505505

activerecord/lib/active_record/connection_adapters/mysql/quoting.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ def quoted_binary(value)
5454
"x'#{value.hex}'"
5555
end
5656

57+
def unquote_identifier(identifier)
58+
if identifier && identifier.start_with?("`")
59+
identifier[1..-2]
60+
else
61+
identifier
62+
end
63+
end
64+
5765
# Override +type_cast+ we pass to mysql2 Date and Time objects instead
5866
# of Strings since mysql2 is able to handle those classes more efficiently.
5967
def type_cast(value) # :nodoc:

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ def foreign_keys(table_name)
531531

532532
fk_info.map do |row|
533533
options = {
534-
column: row["column"],
534+
column: Utils.unquote_identifier(row["column"]),
535535
name: row["name"],
536536
primary_key: row["primary_key"]
537537
}
@@ -541,8 +541,9 @@ def foreign_keys(table_name)
541541
options[:deferrable] = extract_foreign_key_deferrable(row["deferrable"], row["deferred"])
542542

543543
options[:validate] = row["valid"]
544+
to_table = Utils.unquote_identifier(row["to_table"])
544545

545-
ForeignKeyDefinition.new(table_name, row["to_table"], options)
546+
ForeignKeyDefinition.new(table_name, to_table, options)
546547
end
547548
end
548549

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

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class Name # :nodoc:
1212
attr_reader :schema, :identifier
1313

1414
def initialize(schema, identifier)
15-
@schema, @identifier = unquote(schema), unquote(identifier)
15+
@schema, @identifier = Utils.unquote_identifier(schema), Utils.unquote_identifier(identifier)
1616
end
1717

1818
def to_s
@@ -40,15 +40,6 @@ def hash
4040
def parts
4141
@parts ||= [@schema, @identifier].compact
4242
end
43-
44-
private
45-
def unquote(part)
46-
if part && part.start_with?('"')
47-
part[1..-2]
48-
else
49-
part
50-
end
51-
end
5243
end
5344

5445
module Utils # :nodoc:
@@ -74,6 +65,14 @@ def extract_schema_qualified_name(string)
7465
end
7566
PostgreSQL::Name.new(schema, table)
7667
end
68+
69+
def unquote_identifier(identifier)
70+
if identifier && identifier.start_with?('"')
71+
identifier[1..-2]
72+
else
73+
identifier
74+
end
75+
end
7776
end
7877
end
7978
end

activerecord/test/cases/migration/foreign_key_test.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,16 @@ def test_foreign_key_exists
340340
assert_not @connection.foreign_key_exists?(:astronauts, :stars)
341341
end
342342

343+
def test_foreign_key_exists_referencing_table_having_keyword_as_name
344+
@connection.create_table :user, force: true
345+
@connection.add_column :rockets, :user_id, :bigint
346+
@connection.add_foreign_key :rockets, :user
347+
assert @connection.foreign_key_exists?(:rockets, :user)
348+
ensure
349+
@connection.remove_foreign_key :rockets, :user
350+
@connection.drop_table :user
351+
end
352+
343353
def test_foreign_key_exists_by_column
344354
@connection.add_foreign_key :astronauts, :rockets, column: "rocket_id"
345355

0 commit comments

Comments
 (0)