Skip to content

Commit

Permalink
Fix duplicate escaping of quotes for check constraint expressions in …
Browse files Browse the repository at this point in the history
…MySQL schema

Mysql automatically escapes quotes in generated check constraints expressions.
When Rails dumps the schema (into schema.rb) the generated schema also contains,
the quotes with duplicated escaping (\\\\').
To fix this, we remove the escaping, that MySQL provides from the fetched
expression.
  • Loading branch information
Flixt authored and rafaelfranca committed Sep 26, 2023
1 parent cf44b9e commit 468d3d0
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 0 deletions.
9 changes: 9 additions & 0 deletions activerecord/CHANGELOG.md
@@ -1,3 +1,12 @@
* Fix duplicate quoting for check constraint expressions in schema dump when using MySQL

A check constraint with an expression, that already contains quotes, lead to an invalid schema
dump with the mysql2 adapter.

Fixes #42424.

*Felix Tscheulin*

* Performance tune the SQLite3 adapter connection configuration

For Rails applications, the Write-Ahead-Log in normal syncing mode with a capped journal size, a healthy shared memory buffer and a shared cache will perform, on average, 2× better.
Expand Down
Expand Up @@ -531,6 +531,13 @@ def check_constraints(table_name)
expression = row["expression"]
expression = expression[1..-2] if expression.start_with?("(") && expression.end_with?(")")
expression = strip_whitespace_characters(expression)

unless mariadb?
# MySQL returns check constraints expression in an already escaped form.
# This leads to duplicate escaping later (e.g. when the expression is used in the SchemaDumper).
expression = expression.gsub("\\'", "'")
end

CheckConstraintDefinition.new(table_name, expression, options)
end
else
Expand Down
@@ -0,0 +1,35 @@
# frozen_string_literal: true

require "cases/helper"
require "support/schema_dumping_helper"

if ActiveRecord::Base.connection.supports_check_constraints?
class Mysql2CheckConstraintQuotingTest < ActiveRecord::Mysql2TestCase
include SchemaDumpingHelper

setup do
@connection = ActiveRecord::Base.connection
@connection.create_table "trades", force: true do |t|
t.string :name
end
end

teardown do
@connection.drop_table "trades", if_exists: true rescue nil
end

def test_check_constraint_no_duplicate_expression_quoting
@connection.add_check_constraint :trades, "name != 'forbidden_string'"

check_constraints = @connection.check_constraints("trades")
assert_equal 1, check_constraints.size

expression = check_constraints.first.expression
if ActiveRecord::Base.connection.mariadb?
assert_equal "`name` <> 'forbidden_string'", expression
else
assert_equal "`name` <> _utf8mb4'forbidden_string'", expression
end
end
end
end

0 comments on commit 468d3d0

Please sign in to comment.