1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Fixed MariaDB default function

Dont test default function on MySQL where it is unsupported and default expect default function instead of default value

Simplified test - dont repeat last test

Removed cache of create table SQL - it messes up when tables change, and it should only be called when a default is set and the other cases arent true anyway

Test if string first (starts with single quote) because default_type does a SQL lookup and is more expensive

Fixed tests: Postgres uses a different named method for generating UUID's

Skip check if column default is a function when it starts with a number to reduce the number of queries done

Added note in CHANGELOG.md
This commit is contained in:
kaspernj 2022-03-10 08:32:43 +00:00
parent 2c21a39493
commit 4ccd79cdd6
4 changed files with 75 additions and 2 deletions

View file

@ -1,3 +1,11 @@
* Fixed MariaDB default function support.
Defaults would be written wrong in "db/schema.rb" and not work correctly
if using `db:schema:load`. Further more the function name would be
added as string content when saving new records.
*kaspernj*
* Add `active_record.destroy_association_async_batch_size` configuration
This allows applications to specify the maximum number of records that will

View file

@ -158,7 +158,27 @@ module ActiveRecord
MySQL::TableDefinition.new(self, name, **options)
end
def default_type(table_name, field_name)
match = create_table_sql(table_name).match(/`#{field_name}` (.+) DEFAULT ('|\d+|[A-z]+)/)
default_pre = match[2] if match
if default_pre == "'"
:string
elsif default_pre&.match?(/^\d+$/)
:integer
elsif default_pre&.match?(/^[A-z]+$/)
:function
end
end
def create_table_sql(table_name)
execute_and_free("SHOW CREATE TABLE #{quote_table_name(table_name)}") do |result|
result.first[1]
end
end
def new_column_from_field(table_name, field)
field_name = field.fetch(:Field)
type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
default, default_function = field[:Default], nil
@ -168,9 +188,13 @@ module ActiveRecord
elsif type_metadata.extra == "DEFAULT_GENERATED"
default = +"(#{default})" unless default.start_with?("(")
default, default_function = nil, default
elsif type_metadata.type == :text && default
elsif type_metadata.type == :text && default&.start_with?("'")
# strip and unescape quotes
default = default[1...-1].gsub("\\'", "'")
elsif default&.match?(/\A\d/)
# Its a number so we can skip the query to check if it is a function
elsif default && default_type(table_name, field_name) == :function
default, default_function = nil, default
end
MySQL::Column.new(

View file

@ -1347,6 +1347,32 @@ if ActiveRecord::Base.connection.supports_bulk_alter?
assert_equal "This is a comment", column(:birthdate).comment
end
if supports_text_column_with_default?
def test_default_functions_on_columns
with_bulk_change_table do |t|
if current_adapter?(:PostgreSQLAdapter)
t.string :name, default: -> { "gen_random_uuid()" }
else
t.string :name, default: -> { "UUID()" }
end
end
assert_nil column(:name).default
if current_adapter?(:PostgreSQLAdapter)
assert_equal "gen_random_uuid()", column(:name).default_function
Person.connection.execute("INSERT INTO delete_me DEFAULT VALUES")
person_data = Person.connection.execute("SELECT * FROM delete_me ORDER BY id DESC").to_a.first
else
assert_equal "uuid()", column(:name).default_function
Person.connection.execute("INSERT INTO delete_me () VALUES ()")
person_data = Person.connection.execute("SELECT * FROM delete_me ORDER BY id DESC").to_a(as: :hash).first
end
assert_match(/\A(.+)-(.+)-(.+)-(.+)\Z/, person_data.fetch("name"))
end
end
if current_adapter?(:Mysql2Adapter)
def test_updating_auto_increment
with_bulk_change_table do |t|

View file

@ -825,7 +825,16 @@ class SchemaDumperDefaultsTest < ActiveRecord::TestCase
t.datetime :datetime_with_default, default: "2014-06-05 07:17:04"
t.time :time_with_default, default: "07:17:04"
t.decimal :decimal_with_default, default: "1234567890.0123456789", precision: 20, scale: 10
t.text :text_with_default, default: "John' Doe" if supports_text_column_with_default?
if supports_text_column_with_default?
t.text :text_with_default, default: "John' Doe"
if current_adapter?(:PostgreSQLAdapter)
t.text :uuid, default: -> { "gen_random_uuid()" }
else
t.text :uuid, default: -> { "uuid()" }
end
end
end
if current_adapter?(:PostgreSQLAdapter)
@ -864,6 +873,12 @@ class SchemaDumperDefaultsTest < ActiveRecord::TestCase
output = dump_table_schema("dump_defaults")
assert_match %r{t\.text\s+"text_with_default",.*?default: "John' Doe"}, output
if current_adapter?(:PostgreSQLAdapter)
assert_match %r{t\.text\s+"uuid",.*?default: -> \{ "gen_random_uuid\(\)" \}}, output
else
assert_match %r{t\.text\s+"uuid",.*?default: -> \{ "uuid\(\)" \}}, output
end
end if supports_text_column_with_default?
def test_schema_dump_with_column_infinity_default