Add support for check_constraints with the same name on different tables

- MariaDB allows the use of the same check_constraint name as long as it
 is on a different table. This is done by adding a new column to the
 information_schema.check_constraints table with name table_name.
This commit is contained in:
Daniel Alfaro 2021-03-29 10:43:53 -07:00
parent 6ce14ee4bc
commit 010a4a6e5f
3 changed files with 38 additions and 1 deletions

View File

@ -427,7 +427,7 @@ module ActiveRecord
if supports_check_constraints?
scope = quoted_scope(table_name)
chk_info = exec_query(<<~SQL, "SCHEMA")
sql = <<~SQL
SELECT cc.constraint_name AS 'name',
cc.check_clause AS 'expression'
FROM information_schema.check_constraints cc
@ -437,6 +437,9 @@ module ActiveRecord
AND tc.table_name = #{scope[:name]}
AND cc.constraint_schema = #{scope[:schema]}
SQL
sql += " AND cc.table_name = #{scope[:name]}" if mariadb?
chk_info = exec_query(sql, "SCHEMA")
chk_info.map do |row|
options = {

View File

@ -54,6 +54,15 @@ def supports_default_expression?
end
end
def supports_non_unique_constraint_name?
if current_adapter?(:Mysql2Adapter)
conn = ActiveRecord::Base.connection
conn.mariadb?
else
false
end
end
%w[
supports_savepoints?
supports_partial_index?

View File

@ -18,10 +18,16 @@ if ActiveRecord::Base.connection.supports_check_constraints?
t.integer :price
t.integer :quantity
end
@connection.create_table "purchases", force: true do |t|
t.integer :price
t.integer :quantity
end
end
teardown do
@connection.drop_table "trades", if_exists: true rescue nil
@connection.drop_table "purchases", if_exists: true rescue nil
end
def test_check_constraints
@ -56,6 +62,25 @@ if ActiveRecord::Base.connection.supports_check_constraints?
end
end
if supports_non_unique_constraint_name?
def test_add_constraint_with_same_name_to_different_table
@connection.add_check_constraint :trades, "quantity > 0", name: "greater_than_zero"
@connection.add_check_constraint :purchases, "quantity > 0", name: "greater_than_zero"
trades_check_constraints = @connection.check_constraints("trades")
assert_equal 1, trades_check_constraints.size
trade_constraint = trades_check_constraints.first
assert_equal "trades", trade_constraint.table_name
assert_equal "greater_than_zero", trade_constraint.name
purchases_check_constraints = @connection.check_constraints("purchases")
assert_equal 1, purchases_check_constraints.size
purchase_constraint = purchases_check_constraints.first
assert_equal "purchases", purchase_constraint.table_name
assert_equal "greater_than_zero", purchase_constraint.name
end
end
def test_add_check_constraint_with_non_existent_table_raises
e = assert_raises(ActiveRecord::StatementInvalid) do
@connection.add_check_constraint :refunds, "quantity > 0", name: "quantity_check"