activerecord 5.2.8.1 → 6.0.6
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +919 -573
- data/MIT-LICENSE +3 -1
- data/README.rdoc +5 -3
- data/examples/performance.rb +1 -1
- data/lib/active_record/advisory_lock_base.rb +18 -0
- data/lib/active_record/aggregations.rb +4 -3
- data/lib/active_record/association_relation.rb +10 -8
- data/lib/active_record/associations/alias_tracker.rb +0 -1
- data/lib/active_record/associations/association.rb +55 -19
- data/lib/active_record/associations/association_scope.rb +11 -7
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +3 -13
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +19 -23
- data/lib/active_record/associations/collection_proxy.rb +14 -17
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -11
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +4 -4
- data/lib/active_record/associations/join_dependency.rb +47 -30
- data/lib/active_record/associations/preloader/association.rb +61 -41
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/preloader.rb +44 -33
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +21 -16
- data/lib/active_record/attribute_assignment.rb +7 -11
- data/lib/active_record/attribute_decorators.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -24
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -54
- data/lib/active_record/attribute_methods/serialization.rb +1 -2
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
- data/lib/active_record/attribute_methods/write.rb +17 -25
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attributes.rb +13 -1
- data/lib/active_record/autosave_association.rb +12 -14
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +6 -21
- data/lib/active_record/coders/yaml_column.rb +15 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -18
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
- data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +105 -72
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
- data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -217
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +63 -75
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +137 -147
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +139 -26
- data/lib/active_record/core.rb +108 -67
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +78 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +44 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +144 -474
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +13 -6
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +11 -3
- data/lib/active_record/locking/optimistic.rb +14 -7
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +8 -27
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
- data/lib/active_record/middleware/database_selector.rb +74 -0
- data/lib/active_record/migration/command_recorder.rb +54 -22
- data/lib/active_record/migration/compatibility.rb +79 -52
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +104 -85
- data/lib/active_record/model_schema.rb +62 -11
- data/lib/active_record/nested_attributes.rb +2 -4
- data/lib/active_record/no_touching.rb +9 -2
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +232 -29
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +33 -21
- data/lib/active_record/railtie.rb +80 -61
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +199 -46
- data/lib/active_record/reflection.rb +51 -51
- data/lib/active_record/relation/batches.rb +13 -11
- data/lib/active_record/relation/calculations.rb +55 -49
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +23 -28
- data/lib/active_record/relation/from_clause.rb +4 -0
- data/lib/active_record/relation/merger.rb +12 -17
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder.rb +5 -11
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +232 -69
- data/lib/active_record/relation/spawn_methods.rb +1 -2
- data/lib/active_record/relation/where_clause.rb +14 -11
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/relation.rb +326 -81
- data/lib/active_record/result.rb +30 -12
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +6 -2
- data/lib/active_record/scoping/default.rb +4 -6
- data/lib/active_record/scoping/named.rb +25 -16
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/statement_cache.rb +30 -3
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +23 -15
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +243 -0
- data/lib/active_record/timestamp.rb +39 -26
- data/lib/active_record/touch_later.rb +5 -4
- data/lib/active_record/transactions.rb +64 -73
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +3 -13
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +0 -1
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +3 -5
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/associated.rb +0 -1
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +10 -2
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +256 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +203 -0
- data/lib/arel/visitors/dot.rb +296 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +156 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +158 -0
- data/lib/arel/visitors/oracle12.rb +65 -0
- data/lib/arel/visitors/postgresql.rb +109 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +888 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors/where_sql.rb +22 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +62 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/migration.rb +14 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +112 -25
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -10,6 +10,10 @@ module ActiveRecord
|
|
10
10
|
spec[:unsigned] = "true" if column.unsigned?
|
11
11
|
spec[:auto_increment] = "true" if column.auto_increment?
|
12
12
|
|
13
|
+
if /\A(?<size>tiny|medium|long)(?:text|blob)/ =~ column.sql_type
|
14
|
+
spec = { size: size.to_sym.inspect }.merge!(spec)
|
15
|
+
end
|
16
|
+
|
13
17
|
if @connection.supports_virtual_columns? && column.virtual?
|
14
18
|
spec[:as] = extract_expression_for_virtual_column(column)
|
15
19
|
spec[:stored] = "true" if /\b(?:STORED|PERSISTENT)\b/.match?(column.extra)
|
@@ -37,19 +41,23 @@ module ActiveRecord
|
|
37
41
|
case column.sql_type
|
38
42
|
when /\Atimestamp\b/
|
39
43
|
:timestamp
|
40
|
-
when
|
41
|
-
|
44
|
+
when /\A(?:enum|set)\b/
|
45
|
+
column.sql_type
|
42
46
|
else
|
43
47
|
super
|
44
48
|
end
|
45
49
|
end
|
46
50
|
|
51
|
+
def schema_limit(column)
|
52
|
+
super unless /\A(?:enum|set|(?:tiny|medium|long)?(?:text|blob))\b/.match?(column.sql_type)
|
53
|
+
end
|
54
|
+
|
47
55
|
def schema_precision(column)
|
48
56
|
super unless /\A(?:date)?time(?:stamp)?\b/.match?(column.sql_type) && column.precision == 0
|
49
57
|
end
|
50
58
|
|
51
59
|
def schema_collation(column)
|
52
|
-
if column.collation
|
60
|
+
if column.collation
|
53
61
|
@table_collation_cache ||= {}
|
54
62
|
@table_collation_cache[table_name] ||=
|
55
63
|
@connection.exec_query("SHOW TABLE STATUS LIKE #{@connection.quote(table_name)}", "SCHEMA").first["Collation"]
|
@@ -58,14 +66,14 @@ module ActiveRecord
|
|
58
66
|
end
|
59
67
|
|
60
68
|
def extract_expression_for_virtual_column(column)
|
61
|
-
if @connection.mariadb? && @connection.
|
62
|
-
create_table_info = @connection.send(:create_table_info,
|
69
|
+
if @connection.mariadb? && @connection.database_version < "10.2.5"
|
70
|
+
create_table_info = @connection.send(:create_table_info, table_name)
|
63
71
|
column_name = @connection.quote_column_name(column.name)
|
64
72
|
if %r/#{column_name} #{Regexp.quote(column.sql_type)}(?: COLLATE \w+)? AS \((?<expression>.+?)\) #{column.extra}/ =~ create_table_info
|
65
73
|
$~[:expression].inspect
|
66
74
|
end
|
67
75
|
else
|
68
|
-
scope = @connection.send(:quoted_scope,
|
76
|
+
scope = @connection.send(:quoted_scope, table_name)
|
69
77
|
column_name = @connection.quote(column.name)
|
70
78
|
sql = "SELECT generation_expression FROM information_schema.columns" \
|
71
79
|
" WHERE table_schema = #{scope[:schema]}" \
|
@@ -35,25 +35,55 @@ module ActiveRecord
|
|
35
35
|
]
|
36
36
|
end
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
if row[:Expression]
|
39
|
+
expression = row[:Expression]
|
40
|
+
expression = +"(#{expression})" unless expression.start_with?("(")
|
41
|
+
indexes.last[-2] << expression
|
42
|
+
indexes.last[-1][:expressions] ||= {}
|
43
|
+
indexes.last[-1][:expressions][expression] = expression
|
44
|
+
indexes.last[-1][:orders][expression] = :desc if row[:Collation] == "D"
|
45
|
+
else
|
46
|
+
indexes.last[-2] << row[:Column_name]
|
47
|
+
indexes.last[-1][:lengths][row[:Column_name]] = row[:Sub_part].to_i if row[:Sub_part]
|
48
|
+
indexes.last[-1][:orders][row[:Column_name]] = :desc if row[:Collation] == "D"
|
49
|
+
end
|
41
50
|
end
|
42
51
|
end
|
43
52
|
|
44
|
-
indexes.map
|
53
|
+
indexes.map do |index|
|
54
|
+
options = index.pop
|
55
|
+
|
56
|
+
if expressions = options.delete(:expressions)
|
57
|
+
orders = options.delete(:orders)
|
58
|
+
lengths = options.delete(:lengths)
|
59
|
+
|
60
|
+
columns = index[-1].map { |name|
|
61
|
+
[ name.to_sym, expressions[name] || +quote_column_name(name) ]
|
62
|
+
}.to_h
|
63
|
+
|
64
|
+
index[-1] = add_options_for_index_columns(
|
65
|
+
columns, order: orders, length: lengths
|
66
|
+
).values.join(", ")
|
67
|
+
end
|
68
|
+
|
69
|
+
IndexDefinition.new(*index, **options)
|
70
|
+
end
|
45
71
|
end
|
46
72
|
|
47
|
-
def remove_column(table_name, column_name, type = nil, options
|
73
|
+
def remove_column(table_name, column_name, type = nil, **options)
|
48
74
|
if foreign_key_exists?(table_name, column: column_name)
|
49
75
|
remove_foreign_key(table_name, column: column_name)
|
50
76
|
end
|
51
77
|
super
|
52
78
|
end
|
53
79
|
|
80
|
+
def create_table(table_name, options: default_row_format, **)
|
81
|
+
super
|
82
|
+
end
|
83
|
+
|
54
84
|
def internal_string_options_for_primary_key
|
55
85
|
super.tap do |options|
|
56
|
-
if CHARSETS_OF_4BYTES_MAXLEN.include?(charset)
|
86
|
+
if !row_format_dynamic_by_default? && CHARSETS_OF_4BYTES_MAXLEN.include?(charset)
|
57
87
|
options[:collation] = collation.sub(/\A[^_]+/, "utf8")
|
58
88
|
end
|
59
89
|
end
|
@@ -67,23 +97,76 @@ module ActiveRecord
|
|
67
97
|
MySQL::SchemaDumper.create(self, options)
|
68
98
|
end
|
69
99
|
|
100
|
+
# Maps logical Rails types to MySQL-specific data types.
|
101
|
+
def type_to_sql(type, limit: nil, precision: nil, scale: nil, size: limit_to_size(limit, type), unsigned: nil, **)
|
102
|
+
sql =
|
103
|
+
case type.to_s
|
104
|
+
when "integer"
|
105
|
+
integer_to_sql(limit)
|
106
|
+
when "text"
|
107
|
+
type_with_size_to_sql("text", size)
|
108
|
+
when "blob"
|
109
|
+
type_with_size_to_sql("blob", size)
|
110
|
+
when "binary"
|
111
|
+
if (0..0xfff) === limit
|
112
|
+
"varbinary(#{limit})"
|
113
|
+
else
|
114
|
+
type_with_size_to_sql("blob", size)
|
115
|
+
end
|
116
|
+
else
|
117
|
+
super
|
118
|
+
end
|
119
|
+
|
120
|
+
sql = "#{sql} unsigned" if unsigned && type != :primary_key
|
121
|
+
sql
|
122
|
+
end
|
123
|
+
|
124
|
+
def table_alias_length
|
125
|
+
256 # https://dev.mysql.com/doc/refman/8.0/en/identifiers.html
|
126
|
+
end
|
127
|
+
|
70
128
|
private
|
71
129
|
CHARSETS_OF_4BYTES_MAXLEN = ["utf8mb4", "utf16", "utf16le", "utf32"]
|
72
130
|
|
131
|
+
def row_format_dynamic_by_default?
|
132
|
+
if mariadb?
|
133
|
+
database_version >= "10.2.2"
|
134
|
+
else
|
135
|
+
database_version >= "5.7.9"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def default_row_format
|
140
|
+
return if row_format_dynamic_by_default?
|
141
|
+
|
142
|
+
unless defined?(@default_row_format)
|
143
|
+
if query_value("SELECT @@innodb_file_per_table = 1 AND @@innodb_file_format = 'Barracuda'") == 1
|
144
|
+
@default_row_format = "ROW_FORMAT=DYNAMIC"
|
145
|
+
else
|
146
|
+
@default_row_format = nil
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
@default_row_format
|
151
|
+
end
|
152
|
+
|
73
153
|
def schema_creation
|
74
154
|
MySQL::SchemaCreation.new(self)
|
75
155
|
end
|
76
156
|
|
77
|
-
def create_table_definition(*args)
|
78
|
-
MySQL::TableDefinition.new(*args)
|
157
|
+
def create_table_definition(*args, **options)
|
158
|
+
MySQL::TableDefinition.new(self, *args, **options)
|
79
159
|
end
|
80
160
|
|
81
161
|
def new_column_from_field(table_name, field)
|
82
162
|
type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
default, default_function =
|
163
|
+
default, default_function = field[:Default], nil
|
164
|
+
|
165
|
+
if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(default)
|
166
|
+
default, default_function = nil, default
|
167
|
+
elsif type_metadata.extra == "DEFAULT_GENERATED"
|
168
|
+
default = +"(#{default})" unless default.start_with?("(")
|
169
|
+
default, default_function = nil, default
|
87
170
|
end
|
88
171
|
|
89
172
|
MySQL::Column.new(
|
@@ -91,9 +174,8 @@ module ActiveRecord
|
|
91
174
|
default,
|
92
175
|
type_metadata,
|
93
176
|
field[:Null] == "YES",
|
94
|
-
table_name,
|
95
177
|
default_function,
|
96
|
-
field[:Collation],
|
178
|
+
collation: field[:Collation],
|
97
179
|
comment: field[:Comment].presence
|
98
180
|
)
|
99
181
|
end
|
@@ -114,17 +196,21 @@ module ActiveRecord
|
|
114
196
|
end
|
115
197
|
|
116
198
|
def add_options_for_index_columns(quoted_columns, **options)
|
117
|
-
quoted_columns = add_index_length(quoted_columns, options)
|
199
|
+
quoted_columns = add_index_length(quoted_columns, **options)
|
118
200
|
super
|
119
201
|
end
|
120
202
|
|
121
203
|
def data_source_sql(name = nil, type: nil)
|
122
204
|
scope = quoted_scope(name, type: type)
|
123
205
|
|
124
|
-
sql = "SELECT table_name FROM information_schema.tables"
|
125
|
-
sql << " WHERE table_schema = #{scope[:schema]}"
|
126
|
-
|
127
|
-
|
206
|
+
sql = +"SELECT table_name FROM (SELECT * FROM information_schema.tables "
|
207
|
+
sql << " WHERE table_schema = #{scope[:schema]}) _subquery"
|
208
|
+
if scope[:type] || scope[:name]
|
209
|
+
conditions = []
|
210
|
+
conditions << "_subquery.table_type = #{scope[:type]}" if scope[:type]
|
211
|
+
conditions << "_subquery.table_name = #{scope[:name]}" if scope[:name]
|
212
|
+
sql << " WHERE #{conditions.join(" AND ")}"
|
213
|
+
end
|
128
214
|
sql
|
129
215
|
end
|
130
216
|
|
@@ -142,6 +228,40 @@ module ActiveRecord
|
|
142
228
|
schema, name = nil, schema unless name
|
143
229
|
[schema, name]
|
144
230
|
end
|
231
|
+
|
232
|
+
def type_with_size_to_sql(type, size)
|
233
|
+
case size&.to_s
|
234
|
+
when nil, "tiny", "medium", "long"
|
235
|
+
"#{size}#{type}"
|
236
|
+
else
|
237
|
+
raise ArgumentError,
|
238
|
+
"#{size.inspect} is invalid :size value. Only :tiny, :medium, and :long are allowed."
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def limit_to_size(limit, type)
|
243
|
+
case type.to_s
|
244
|
+
when "text", "blob", "binary"
|
245
|
+
case limit
|
246
|
+
when 0..0xff; "tiny"
|
247
|
+
when nil, 0x100..0xffff; nil
|
248
|
+
when 0x10000..0xffffff; "medium"
|
249
|
+
when 0x1000000..0xffffffff; "long"
|
250
|
+
else raise ArgumentError, "No #{type} type has byte size #{limit}"
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def integer_to_sql(limit)
|
256
|
+
case limit
|
257
|
+
when 1; "tinyint"
|
258
|
+
when 2; "smallint"
|
259
|
+
when 3; "mediumint"
|
260
|
+
when nil, 4; "int"
|
261
|
+
when 5..8; "bigint"
|
262
|
+
else raise ArgumentError, "No integer type has byte size #{limit}. Use a decimal with scale 0 instead."
|
263
|
+
end
|
264
|
+
end
|
145
265
|
end
|
146
266
|
end
|
147
267
|
end
|
@@ -10,25 +10,21 @@ module ActiveRecord
|
|
10
10
|
|
11
11
|
def initialize(type_metadata, extra: "")
|
12
12
|
super(type_metadata)
|
13
|
-
@type_metadata = type_metadata
|
14
13
|
@extra = extra
|
15
14
|
end
|
16
15
|
|
17
16
|
def ==(other)
|
18
|
-
other.is_a?(
|
19
|
-
|
17
|
+
other.is_a?(TypeMetadata) &&
|
18
|
+
__getobj__ == other.__getobj__ &&
|
19
|
+
extra == other.extra
|
20
20
|
end
|
21
21
|
alias eql? ==
|
22
22
|
|
23
23
|
def hash
|
24
|
-
|
24
|
+
TypeMetadata.hash ^
|
25
|
+
__getobj__.hash ^
|
26
|
+
extra.hash
|
25
27
|
end
|
26
|
-
|
27
|
-
protected
|
28
|
-
|
29
|
-
def attributes_for_hash
|
30
|
-
[self.class, @type_metadata, extra]
|
31
|
-
end
|
32
28
|
end
|
33
29
|
end
|
34
30
|
end
|
@@ -3,18 +3,20 @@
|
|
3
3
|
require "active_record/connection_adapters/abstract_mysql_adapter"
|
4
4
|
require "active_record/connection_adapters/mysql/database_statements"
|
5
5
|
|
6
|
-
gem "mysql2", ">= 0.4.4"
|
6
|
+
gem "mysql2", ">= 0.4.4"
|
7
7
|
require "mysql2"
|
8
8
|
|
9
9
|
module ActiveRecord
|
10
10
|
module ConnectionHandling # :nodoc:
|
11
|
+
ER_BAD_DB_ERROR = 1049
|
12
|
+
|
11
13
|
# Establishes a connection to the database that's used by all Active Record objects.
|
12
14
|
def mysql2_connection(config)
|
13
15
|
config = config.symbolize_keys
|
14
16
|
config[:flags] ||= 0
|
15
17
|
|
16
18
|
if config[:flags].kind_of? Array
|
17
|
-
config[:flags].push "FOUND_ROWS"
|
19
|
+
config[:flags].push "FOUND_ROWS"
|
18
20
|
else
|
19
21
|
config[:flags] |= Mysql2::Client::FOUND_ROWS
|
20
22
|
end
|
@@ -22,7 +24,7 @@ module ActiveRecord
|
|
22
24
|
client = Mysql2::Client.new(config)
|
23
25
|
ConnectionAdapters::Mysql2Adapter.new(client, logger, nil, config)
|
24
26
|
rescue Mysql2::Error => error
|
25
|
-
if error.
|
27
|
+
if error.error_number == ER_BAD_DB_ERROR
|
26
28
|
raise ActiveRecord::NoDatabaseError
|
27
29
|
else
|
28
30
|
raise
|
@@ -32,18 +34,24 @@ module ActiveRecord
|
|
32
34
|
|
33
35
|
module ConnectionAdapters
|
34
36
|
class Mysql2Adapter < AbstractMysqlAdapter
|
35
|
-
ADAPTER_NAME = "Mysql2"
|
37
|
+
ADAPTER_NAME = "Mysql2"
|
36
38
|
|
37
39
|
include MySQL::DatabaseStatements
|
38
40
|
|
39
41
|
def initialize(connection, logger, connection_options, config)
|
40
|
-
|
41
|
-
|
42
|
+
superclass_config = config.reverse_merge(prepared_statements: false)
|
43
|
+
super(connection, logger, connection_options, superclass_config)
|
42
44
|
configure_connection
|
43
45
|
end
|
44
46
|
|
47
|
+
def self.database_exists?(config)
|
48
|
+
!!ActiveRecord::Base.mysql2_connection(config)
|
49
|
+
rescue ActiveRecord::NoDatabaseError
|
50
|
+
false
|
51
|
+
end
|
52
|
+
|
45
53
|
def supports_json?
|
46
|
-
!mariadb? &&
|
54
|
+
!mariadb? && database_version >= "5.7.8"
|
47
55
|
end
|
48
56
|
|
49
57
|
def supports_comments?
|
@@ -58,6 +66,10 @@ module ActiveRecord
|
|
58
66
|
true
|
59
67
|
end
|
60
68
|
|
69
|
+
def supports_lazy_transactions?
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
61
73
|
# HELPER METHODS ===========================================
|
62
74
|
|
63
75
|
def each_hash(result) # :nodoc:
|
@@ -105,24 +117,28 @@ module ActiveRecord
|
|
105
117
|
end
|
106
118
|
|
107
119
|
def discard! # :nodoc:
|
120
|
+
super
|
108
121
|
@connection.automatic_close = false
|
109
122
|
@connection = nil
|
110
123
|
end
|
111
124
|
|
112
125
|
private
|
113
|
-
|
114
126
|
def connect
|
115
127
|
@connection = Mysql2::Client.new(@config)
|
116
128
|
configure_connection
|
117
129
|
end
|
118
130
|
|
119
131
|
def configure_connection
|
120
|
-
@connection.query_options
|
132
|
+
@connection.query_options[:as] = :array
|
121
133
|
super
|
122
134
|
end
|
123
135
|
|
124
136
|
def full_version
|
125
|
-
|
137
|
+
schema_cache.database_version.full_version_string
|
138
|
+
end
|
139
|
+
|
140
|
+
def get_full_version
|
141
|
+
@connection.server_info[:version]
|
126
142
|
end
|
127
143
|
end
|
128
144
|
end
|
@@ -2,43 +2,29 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module ConnectionAdapters
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
alias :array? :array
|
5
|
+
module PostgreSQL
|
6
|
+
class Column < ConnectionAdapters::Column # :nodoc:
|
7
|
+
delegate :oid, :fmod, to: :sql_type_metadata
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
def serial?
|
16
|
-
return unless default_function
|
17
|
-
|
18
|
-
if %r{\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z} =~ default_function
|
19
|
-
sequence_name_from_parts(table_name, name, suffix) == sequence_name
|
9
|
+
def initialize(*, serial: nil, **)
|
10
|
+
super
|
11
|
+
@serial = serial
|
20
12
|
end
|
21
|
-
end
|
22
|
-
|
23
|
-
protected
|
24
|
-
attr_reader :max_identifier_length
|
25
13
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
if over_length > 0
|
31
|
-
column_name_length = [(max_identifier_length - suffix.length - 2) / 2, column_name.length].min
|
32
|
-
over_length -= column_name.length - column_name_length
|
33
|
-
column_name = column_name[0, column_name_length - [over_length, 0].min]
|
34
|
-
end
|
14
|
+
def serial?
|
15
|
+
@serial
|
16
|
+
end
|
35
17
|
|
36
|
-
|
37
|
-
|
38
|
-
|
18
|
+
def array
|
19
|
+
sql_type_metadata.sql_type.end_with?("[]")
|
20
|
+
end
|
21
|
+
alias :array? :array
|
39
22
|
|
40
|
-
|
23
|
+
def sql_type
|
24
|
+
super.sub(/\[\]\z/, "")
|
41
25
|
end
|
26
|
+
end
|
42
27
|
end
|
28
|
+
PostgreSQLColumn = PostgreSQL::Column # :nodoc:
|
43
29
|
end
|
44
30
|
end
|
@@ -58,6 +58,8 @@ module ActiveRecord
|
|
58
58
|
|
59
59
|
# Queries the database and returns the results in an Array-like object
|
60
60
|
def query(sql, name = nil) #:nodoc:
|
61
|
+
materialize_transactions
|
62
|
+
|
61
63
|
log(sql, name) do
|
62
64
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
63
65
|
result_as_array @connection.async_exec(sql)
|
@@ -65,11 +67,26 @@ module ActiveRecord
|
|
65
67
|
end
|
66
68
|
end
|
67
69
|
|
70
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
71
|
+
:close, :declare, :fetch, :move, :set, :show
|
72
|
+
) # :nodoc:
|
73
|
+
private_constant :READ_QUERY
|
74
|
+
|
75
|
+
def write_query?(sql) # :nodoc:
|
76
|
+
!READ_QUERY.match?(sql)
|
77
|
+
end
|
78
|
+
|
68
79
|
# Executes an SQL statement, returning a PG::Result object on success
|
69
80
|
# or raising a PG::Error exception otherwise.
|
70
81
|
# Note: the PG::Result object is manually memory managed; if you don't
|
71
82
|
# need it specifically, you may want consider the <tt>exec_query</tt> wrapper.
|
72
83
|
def execute(sql, name = nil)
|
84
|
+
if preventing_writes? && write_query?(sql)
|
85
|
+
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
86
|
+
end
|
87
|
+
|
88
|
+
materialize_transactions
|
89
|
+
|
73
90
|
log(sql, name) do
|
74
91
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
75
92
|
@connection.async_exec(sql)
|
@@ -95,7 +112,7 @@ module ActiveRecord
|
|
95
112
|
end
|
96
113
|
alias :exec_update :exec_delete
|
97
114
|
|
98
|
-
def sql_for_insert(sql, pk,
|
115
|
+
def sql_for_insert(sql, pk, binds) # :nodoc:
|
99
116
|
if pk.nil?
|
100
117
|
# Extract the table from the insert sql. Yuck.
|
101
118
|
table_ref = extract_table_ref_from_insert_sql(sql)
|
@@ -149,6 +166,14 @@ module ActiveRecord
|
|
149
166
|
end
|
150
167
|
|
151
168
|
private
|
169
|
+
def execute_batch(statements, name = nil)
|
170
|
+
execute(combine_multi_statements(statements))
|
171
|
+
end
|
172
|
+
|
173
|
+
def build_truncate_statements(table_names)
|
174
|
+
["TRUNCATE TABLE #{table_names.map(&method(:quote_table_name)).join(", ")}"]
|
175
|
+
end
|
176
|
+
|
152
177
|
# Returns the current ID of a table's sequence.
|
153
178
|
def last_insert_id_result(sequence_name)
|
154
179
|
exec_query("SELECT currval(#{quote(sequence_name)})", "SQL")
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
module PostgreSQL
|
6
6
|
module OID # :nodoc:
|
7
7
|
class Array < Type::Value # :nodoc:
|
8
|
-
include Type::Helpers::Mutable
|
8
|
+
include ActiveModel::Type::Helpers::Mutable
|
9
9
|
|
10
10
|
Data = Struct.new(:encoder, :values) # :nodoc:
|
11
11
|
|
@@ -77,7 +77,6 @@ module ActiveRecord
|
|
77
77
|
end
|
78
78
|
|
79
79
|
private
|
80
|
-
|
81
80
|
def type_cast_array(value, method)
|
82
81
|
if value.is_a?(::Array)
|
83
82
|
value.map { |item| type_cast_array(item, method) }
|
@@ -43,10 +43,7 @@ module ActiveRecord
|
|
43
43
|
/\A[0-9A-F]*\Z/i.match?(value)
|
44
44
|
end
|
45
45
|
|
46
|
-
|
47
|
-
# Workaround for Ruby 2.2 "private attribute?" warning.
|
48
|
-
protected
|
49
|
-
|
46
|
+
private
|
50
47
|
attr_reader :value
|
51
48
|
end
|
52
49
|
end
|
@@ -16,6 +16,14 @@ module ActiveRecord
|
|
16
16
|
super
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
def type_cast_for_schema(value)
|
21
|
+
case value
|
22
|
+
when ::Float::INFINITY then "::Float::INFINITY"
|
23
|
+
when -::Float::INFINITY then "-::Float::INFINITY"
|
24
|
+
else super
|
25
|
+
end
|
26
|
+
end
|
19
27
|
end
|
20
28
|
end
|
21
29
|
end
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
module PostgreSQL
|
6
6
|
module OID # :nodoc:
|
7
7
|
class Hstore < Type::Value # :nodoc:
|
8
|
-
include Type::Helpers::Mutable
|
8
|
+
include ActiveModel::Type::Helpers::Mutable
|
9
9
|
|
10
10
|
def type
|
11
11
|
:hstore
|
@@ -46,7 +46,6 @@ module ActiveRecord
|
|
46
46
|
end
|
47
47
|
|
48
48
|
private
|
49
|
-
|
50
49
|
HstorePair = begin
|
51
50
|
quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
|
52
51
|
unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
module PostgreSQL
|
6
6
|
module OID # :nodoc:
|
7
7
|
class LegacyPoint < Type::Value # :nodoc:
|
8
|
-
include Type::Helpers::Mutable
|
8
|
+
include ActiveModel::Type::Helpers::Mutable
|
9
9
|
|
10
10
|
def type
|
11
11
|
:point
|
@@ -34,7 +34,6 @@ module ActiveRecord
|
|
34
34
|
end
|
35
35
|
|
36
36
|
private
|
37
|
-
|
38
37
|
def number_for_point(number)
|
39
38
|
number.to_s.gsub(/\.0$/, "")
|
40
39
|
end
|
@@ -7,7 +7,7 @@ module ActiveRecord
|
|
7
7
|
module PostgreSQL
|
8
8
|
module OID # :nodoc:
|
9
9
|
class Point < Type::Value # :nodoc:
|
10
|
-
include Type::Helpers::Mutable
|
10
|
+
include ActiveModel::Type::Helpers::Mutable
|
11
11
|
|
12
12
|
def type
|
13
13
|
:point
|
@@ -50,7 +50,6 @@ module ActiveRecord
|
|
50
50
|
end
|
51
51
|
|
52
52
|
private
|
53
|
-
|
54
53
|
def number_for_point(number)
|
55
54
|
number.to_s.gsub(/\.0$/, "")
|
56
55
|
end
|