activerecord 4.2.11.3 → 5.0.0
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 +5 -5
- data/CHANGELOG.md +1281 -1204
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record/aggregations.rb +35 -24
- data/lib/active_record/association_relation.rb +3 -3
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +11 -9
- data/lib/active_record/associations/association_scope.rb +73 -102
- data/lib/active_record/associations/belongs_to_association.rb +21 -32
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +7 -19
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +14 -11
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +3 -10
- data/lib/active_record/associations/collection_association.rb +49 -41
- data/lib/active_record/associations/collection_proxy.rb +67 -27
- data/lib/active_record/associations/foreign_association.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +20 -71
- data/lib/active_record/associations/has_many_through_association.rb +8 -47
- data/lib/active_record/associations/has_one_association.rb +12 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
- data/lib/active_record/associations/join_dependency.rb +29 -19
- data/lib/active_record/associations/preloader/association.rb +46 -52
- data/lib/active_record/associations/preloader/collection_association.rb +0 -6
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/through_association.rb +27 -14
- data/lib/active_record/associations/preloader.rb +14 -4
- data/lib/active_record/associations/singular_association.rb +7 -1
- data/lib/active_record/associations/through_association.rb +11 -3
- data/lib/active_record/associations.rb +317 -209
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +68 -18
- data/lib/active_record/attribute_assignment.rb +19 -140
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
- data/lib/active_record/attribute_methods/dirty.rb +46 -86
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -14
- data/lib/active_record/attribute_methods/write.rb +13 -37
- data/lib/active_record/attribute_methods.rb +76 -47
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +6 -4
- data/lib/active_record/attribute_set.rb +30 -3
- data/lib/active_record/attributes.rb +199 -81
- data/lib/active_record/autosave_association.rb +49 -16
- data/lib/active_record/base.rb +32 -23
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +452 -182
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -61
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -10
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +236 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +380 -141
- data/lib/active_record/connection_adapters/abstract/transaction.rb +51 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +141 -59
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +401 -370
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +29 -166
- data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +10 -72
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -57
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +234 -148
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +248 -160
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +149 -192
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +37 -14
- data/lib/active_record/core.rb +89 -107
- data/lib/active_record/counter_cache.rb +13 -24
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +113 -76
- data/lib/active_record/errors.rb +87 -48
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +76 -40
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +18 -2
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +15 -15
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +43 -21
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration.rb +363 -133
- data/lib/active_record/model_schema.rb +129 -41
- data/lib/active_record/nested_attributes.rb +58 -29
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +121 -80
- data/lib/active_record/query_cache.rb +15 -18
- data/lib/active_record/querying.rb +10 -9
- data/lib/active_record/railtie.rb +23 -16
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +69 -46
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +282 -115
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +139 -34
- data/lib/active_record/relation/calculations.rb +79 -108
- data/lib/active_record/relation/delegation.rb +7 -20
- data/lib/active_record/relation/finder_methods.rb +163 -81
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +16 -42
- data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +120 -107
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +308 -244
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +4 -7
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/relation.rb +176 -116
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +95 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +62 -38
- data/lib/active_record/schema_migration.rb +11 -14
- data/lib/active_record/scoping/default.rb +23 -9
- data/lib/active_record/scoping/named.rb +49 -28
- data/lib/active_record/scoping.rb +32 -15
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +16 -14
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +57 -43
- data/lib/active_record/tasks/mysql_database_tasks.rb +6 -14
- data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +20 -9
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +138 -56
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -45
- data/lib/active_record/type/date_time.rb +2 -49
- data/lib/active_record/type/internal/abstract_json.rb +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +15 -14
- data/lib/active_record/type/time.rb +10 -16
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +30 -29
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record.rb +8 -4
- data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -1
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +59 -34
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -31
- data/lib/active_record/type/decimal.rb +0 -64
- data/lib/active_record/type/decimal_without_scale.rb +0 -11
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -59
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -40
- data/lib/active_record/type/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -110
@@ -1,46 +1,35 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
1
|
module ActiveRecord
|
4
2
|
# :stopdoc:
|
5
3
|
module ConnectionAdapters
|
6
4
|
# An abstract definition of a column in a table.
|
7
5
|
class Column
|
8
|
-
|
9
|
-
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF'].to_set
|
10
|
-
|
11
|
-
module Format
|
12
|
-
ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/
|
13
|
-
ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/
|
14
|
-
end
|
6
|
+
attr_reader :name, :default, :sql_type_metadata, :null, :table_name, :default_function, :collation, :comment
|
15
7
|
|
16
|
-
|
17
|
-
|
18
|
-
delegate :type, :precision, :scale, :limit, :klass, :accessor,
|
19
|
-
:text?, :number?, :binary?, :changed?,
|
20
|
-
:type_cast_from_user, :type_cast_from_database, :type_cast_for_database,
|
21
|
-
:type_cast_for_schema,
|
22
|
-
to: :cast_type
|
8
|
+
delegate :precision, :scale, :limit, :type, :sql_type, to: :sql_type_metadata, allow_nil: true
|
23
9
|
|
24
10
|
# Instantiates a new column in the table.
|
25
11
|
#
|
26
|
-
# +name+ is the column's name, such as <tt>supplier_id</tt> in <tt>supplier_id int
|
12
|
+
# +name+ is the column's name, such as <tt>supplier_id</tt> in <tt>supplier_id int</tt>.
|
27
13
|
# +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
|
28
|
-
# +
|
29
|
-
# +sql_type+ is used to extract the column's length, if necessary. For example +60+ in
|
30
|
-
# <tt>company_name varchar(60)</tt>.
|
31
|
-
# It will be mapped to one of the standard Rails SQL types in the <tt>type</tt> attribute.
|
14
|
+
# +sql_type_metadata+ is various information about the type of the column
|
32
15
|
# +null+ determines if this column allows +NULL+ values.
|
33
|
-
def initialize(name, default,
|
34
|
-
@name
|
35
|
-
@
|
36
|
-
@
|
37
|
-
@null
|
38
|
-
@default
|
39
|
-
@default_function =
|
16
|
+
def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil)
|
17
|
+
@name = name.freeze
|
18
|
+
@table_name = table_name
|
19
|
+
@sql_type_metadata = sql_type_metadata
|
20
|
+
@null = null
|
21
|
+
@default = default
|
22
|
+
@default_function = default_function
|
23
|
+
@collation = collation
|
24
|
+
@comment = comment
|
40
25
|
end
|
41
26
|
|
42
27
|
def has_default?
|
43
|
-
!default.nil?
|
28
|
+
!default.nil? || default_function
|
29
|
+
end
|
30
|
+
|
31
|
+
def bigint?
|
32
|
+
/\Abigint\b/ === sql_type
|
44
33
|
end
|
45
34
|
|
46
35
|
# Returns the human name of the column name.
|
@@ -51,19 +40,9 @@ module ActiveRecord
|
|
51
40
|
Base.human_attribute_name(@name)
|
52
41
|
end
|
53
42
|
|
54
|
-
def with_type(type)
|
55
|
-
dup.tap do |clone|
|
56
|
-
clone.instance_variable_set('@cast_type', type)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
43
|
def ==(other)
|
61
|
-
other.
|
62
|
-
|
63
|
-
other.cast_type == cast_type &&
|
64
|
-
other.sql_type == sql_type &&
|
65
|
-
other.null == null &&
|
66
|
-
other.default_function == default_function
|
44
|
+
other.is_a?(Column) &&
|
45
|
+
attributes_for_hash == other.attributes_for_hash
|
67
46
|
end
|
68
47
|
alias :eql? :==
|
69
48
|
|
@@ -71,10 +50,16 @@ module ActiveRecord
|
|
71
50
|
attributes_for_hash.hash
|
72
51
|
end
|
73
52
|
|
74
|
-
|
53
|
+
protected
|
75
54
|
|
76
55
|
def attributes_for_hash
|
77
|
-
[self.class, name, default,
|
56
|
+
[self.class, name, default, sql_type_metadata, null, table_name, default_function, collation]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class NullColumn < Column
|
61
|
+
def initialize(name)
|
62
|
+
super(name, nil)
|
78
63
|
end
|
79
64
|
end
|
80
65
|
end
|
@@ -1,13 +1,12 @@
|
|
1
1
|
require 'uri'
|
2
|
-
require 'active_support/core_ext/string/filters'
|
3
2
|
|
4
3
|
module ActiveRecord
|
5
4
|
module ConnectionAdapters
|
6
5
|
class ConnectionSpecification #:nodoc:
|
7
|
-
attr_reader :config, :adapter_method
|
6
|
+
attr_reader :name, :config, :adapter_method
|
8
7
|
|
9
|
-
def initialize(config, adapter_method)
|
10
|
-
@config, @adapter_method = config, adapter_method
|
8
|
+
def initialize(name, config, adapter_method)
|
9
|
+
@name, @config, @adapter_method = name, config, adapter_method
|
11
10
|
end
|
12
11
|
|
13
12
|
def initialize_dup(original)
|
@@ -34,7 +33,7 @@ module ActiveRecord
|
|
34
33
|
def initialize(url)
|
35
34
|
raise "Database URL cannot be empty" if url.blank?
|
36
35
|
@uri = uri_parser.parse(url)
|
37
|
-
@adapter = @uri.scheme.tr('-', '_')
|
36
|
+
@adapter = @uri.scheme && @uri.scheme.tr('-', '_')
|
38
37
|
@adapter = "postgresql" if @adapter == "postgres"
|
39
38
|
|
40
39
|
if @uri.opaque
|
@@ -165,7 +164,7 @@ module ActiveRecord
|
|
165
164
|
# spec.config
|
166
165
|
# # => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" }
|
167
166
|
#
|
168
|
-
def spec(config)
|
167
|
+
def spec(config, name = nil)
|
169
168
|
spec = resolve(config).symbolize_keys
|
170
169
|
|
171
170
|
raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter)
|
@@ -176,11 +175,18 @@ module ActiveRecord
|
|
176
175
|
rescue Gem::LoadError => e
|
177
176
|
raise Gem::LoadError, "Specified '#{spec[:adapter]}' for database adapter, but the gem is not loaded. Add `gem '#{e.name}'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord)."
|
178
177
|
rescue LoadError => e
|
179
|
-
raise LoadError, "Could not load '#{path_to_adapter}'. Make sure that the adapter in config/database.yml is valid. If you use an adapter other than '
|
178
|
+
raise LoadError, "Could not load '#{path_to_adapter}'. Make sure that the adapter in config/database.yml is valid. If you use an adapter other than 'mysql2', 'postgresql' or 'sqlite3' add the necessary adapter gem to the Gemfile.", e.backtrace
|
180
179
|
end
|
181
180
|
|
182
181
|
adapter_method = "#{spec[:adapter]}_connection"
|
183
|
-
|
182
|
+
|
183
|
+
name ||=
|
184
|
+
if config.is_a?(Symbol)
|
185
|
+
config.to_s
|
186
|
+
else
|
187
|
+
"primary"
|
188
|
+
end
|
189
|
+
ConnectionSpecification.new(name, spec, adapter_method)
|
184
190
|
end
|
185
191
|
|
186
192
|
private
|
@@ -210,30 +216,12 @@ module ActiveRecord
|
|
210
216
|
when Symbol
|
211
217
|
resolve_symbol_connection spec
|
212
218
|
when String
|
213
|
-
|
219
|
+
resolve_url_connection spec
|
214
220
|
when Hash
|
215
221
|
resolve_hash_connection spec
|
216
222
|
end
|
217
223
|
end
|
218
224
|
|
219
|
-
def resolve_string_connection(spec)
|
220
|
-
# Rails has historically accepted a string to mean either
|
221
|
-
# an environment key or a URL spec, so we have deprecated
|
222
|
-
# this ambiguous behaviour and in the future this function
|
223
|
-
# can be removed in favor of resolve_url_connection.
|
224
|
-
if configurations.key?(spec) || spec !~ /:/
|
225
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
226
|
-
Passing a string to ActiveRecord::Base.establish_connection for a
|
227
|
-
configuration lookup is deprecated, please pass a symbol
|
228
|
-
(#{spec.to_sym.inspect}) instead.
|
229
|
-
MSG
|
230
|
-
|
231
|
-
resolve_symbol_connection(spec)
|
232
|
-
else
|
233
|
-
resolve_url_connection(spec)
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
225
|
# Takes the environment such as +:production+ or +:development+.
|
238
226
|
# This requires that the @configurations was initialized with a key that
|
239
227
|
# matches.
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module DetermineIfPreparableVisitor
|
4
|
+
attr_reader :preparable
|
5
|
+
|
6
|
+
def accept(*)
|
7
|
+
@preparable = true
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def visit_Arel_Nodes_In(*)
|
12
|
+
@preparable = false
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def visit_Arel_Nodes_SqlLiteral(*)
|
17
|
+
@preparable = false
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module MySQL
|
4
|
+
class Column < ConnectionAdapters::Column # :nodoc:
|
5
|
+
delegate :strict, :extra, to: :sql_type_metadata, allow_nil: true
|
6
|
+
|
7
|
+
def initialize(*)
|
8
|
+
super
|
9
|
+
assert_valid_default
|
10
|
+
extract_default
|
11
|
+
end
|
12
|
+
|
13
|
+
def has_default?
|
14
|
+
return false if blob_or_text_column? # MySQL forbids defaults on blob and text columns
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def blob_or_text_column?
|
19
|
+
/\A(?:tiny|medium|long)?blob\b/ === sql_type || type == :text
|
20
|
+
end
|
21
|
+
|
22
|
+
def unsigned?
|
23
|
+
/\bunsigned\z/ === sql_type
|
24
|
+
end
|
25
|
+
|
26
|
+
def case_sensitive?
|
27
|
+
collation && collation !~ /_ci\z/
|
28
|
+
end
|
29
|
+
|
30
|
+
def auto_increment?
|
31
|
+
extra == 'auto_increment'
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def extract_default
|
37
|
+
if blob_or_text_column?
|
38
|
+
@default = null || strict ? nil : ''
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def assert_valid_default
|
43
|
+
if blob_or_text_column? && default.present?
|
44
|
+
raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module MySQL
|
4
|
+
module DatabaseStatements
|
5
|
+
# Returns an ActiveRecord::Result instance.
|
6
|
+
def select_all(arel, name = nil, binds = [], preparable: nil)
|
7
|
+
result = if ExplainRegistry.collect? && prepared_statements
|
8
|
+
unprepared_statement { super }
|
9
|
+
else
|
10
|
+
super
|
11
|
+
end
|
12
|
+
@connection.next_result while @connection.more_results?
|
13
|
+
result
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns a record hash with the column names as keys and column values
|
17
|
+
# as values.
|
18
|
+
def select_one(arel, name = nil, binds = [])
|
19
|
+
arel, binds = binds_from_relation(arel, binds)
|
20
|
+
@connection.query_options.merge!(as: :hash)
|
21
|
+
select_result(to_sql(arel, binds), name, binds) do |result|
|
22
|
+
@connection.next_result while @connection.more_results?
|
23
|
+
result.first
|
24
|
+
end
|
25
|
+
ensure
|
26
|
+
@connection.query_options.merge!(as: :array)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns an array of arrays containing the field values.
|
30
|
+
# Order is the same as that returned by +columns+.
|
31
|
+
def select_rows(sql, name = nil, binds = [])
|
32
|
+
select_result(sql, name, binds) do |result|
|
33
|
+
@connection.next_result while @connection.more_results?
|
34
|
+
result.to_a
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Executes the SQL statement in the context of this connection.
|
39
|
+
def execute(sql, name = nil)
|
40
|
+
if @connection
|
41
|
+
# make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
|
42
|
+
# made since we established the connection
|
43
|
+
@connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
|
44
|
+
end
|
45
|
+
|
46
|
+
super
|
47
|
+
end
|
48
|
+
|
49
|
+
def exec_query(sql, name = 'SQL', binds = [], prepare: false)
|
50
|
+
if without_prepared_statement?(binds)
|
51
|
+
execute_and_free(sql, name) do |result|
|
52
|
+
ActiveRecord::Result.new(result.fields, result.to_a) if result
|
53
|
+
end
|
54
|
+
else
|
55
|
+
exec_stmt_and_free(sql, name, binds, cache_stmt: prepare) do |_, result|
|
56
|
+
ActiveRecord::Result.new(result.fields, result.to_a) if result
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def exec_delete(sql, name, binds)
|
62
|
+
if without_prepared_statement?(binds)
|
63
|
+
execute_and_free(sql, name) { @connection.affected_rows }
|
64
|
+
else
|
65
|
+
exec_stmt_and_free(sql, name, binds) { |stmt| stmt.affected_rows }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
alias :exec_update :exec_delete
|
69
|
+
|
70
|
+
protected
|
71
|
+
|
72
|
+
def last_inserted_id(result)
|
73
|
+
@connection.last_id
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def select_result(sql, name = nil, binds = [])
|
79
|
+
if without_prepared_statement?(binds)
|
80
|
+
execute_and_free(sql, name) { |result| yield result }
|
81
|
+
else
|
82
|
+
exec_stmt_and_free(sql, name, binds, cache_stmt: true) { |_, result| yield result }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
|
87
|
+
if @connection
|
88
|
+
# make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
|
89
|
+
# made since we established the connection
|
90
|
+
@connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
|
91
|
+
end
|
92
|
+
|
93
|
+
type_casted_binds = binds.map { |attr| type_cast(attr.value_for_database) }
|
94
|
+
|
95
|
+
log(sql, name, binds) do
|
96
|
+
if cache_stmt
|
97
|
+
cache = @statements[sql] ||= {
|
98
|
+
stmt: @connection.prepare(sql)
|
99
|
+
}
|
100
|
+
stmt = cache[:stmt]
|
101
|
+
else
|
102
|
+
stmt = @connection.prepare(sql)
|
103
|
+
end
|
104
|
+
|
105
|
+
begin
|
106
|
+
result = stmt.execute(*type_casted_binds)
|
107
|
+
rescue Mysql2::Error => e
|
108
|
+
if cache_stmt
|
109
|
+
@statements.delete(sql)
|
110
|
+
else
|
111
|
+
stmt.close
|
112
|
+
end
|
113
|
+
raise e
|
114
|
+
end
|
115
|
+
|
116
|
+
ret = yield stmt, result
|
117
|
+
result.free if result
|
118
|
+
stmt.close unless cache_stmt
|
119
|
+
ret
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module MySQL
|
4
|
+
class ExplainPrettyPrinter # :nodoc:
|
5
|
+
# Pretty prints the result of an EXPLAIN in a way that resembles the output of the
|
6
|
+
# MySQL shell:
|
7
|
+
#
|
8
|
+
# +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
|
9
|
+
# | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|
10
|
+
# +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
|
11
|
+
# | 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | |
|
12
|
+
# | 1 | SIMPLE | posts | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
|
13
|
+
# +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+
|
14
|
+
# 2 rows in set (0.00 sec)
|
15
|
+
#
|
16
|
+
# This is an exercise in Ruby hyperrealism :).
|
17
|
+
def pp(result, elapsed)
|
18
|
+
widths = compute_column_widths(result)
|
19
|
+
separator = build_separator(widths)
|
20
|
+
|
21
|
+
pp = []
|
22
|
+
|
23
|
+
pp << separator
|
24
|
+
pp << build_cells(result.columns, widths)
|
25
|
+
pp << separator
|
26
|
+
|
27
|
+
result.rows.each do |row|
|
28
|
+
pp << build_cells(row, widths)
|
29
|
+
end
|
30
|
+
|
31
|
+
pp << separator
|
32
|
+
pp << build_footer(result.rows.length, elapsed)
|
33
|
+
|
34
|
+
pp.join("\n") + "\n"
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def compute_column_widths(result)
|
40
|
+
[].tap do |widths|
|
41
|
+
result.columns.each_with_index do |column, i|
|
42
|
+
cells_in_column = [column] + result.rows.map {|r| r[i].nil? ? 'NULL' : r[i].to_s}
|
43
|
+
widths << cells_in_column.map(&:length).max
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def build_separator(widths)
|
49
|
+
padding = 1
|
50
|
+
'+' + widths.map {|w| '-' * (w + (padding*2))}.join('+') + '+'
|
51
|
+
end
|
52
|
+
|
53
|
+
def build_cells(items, widths)
|
54
|
+
cells = []
|
55
|
+
items.each_with_index do |item, i|
|
56
|
+
item = 'NULL' if item.nil?
|
57
|
+
justifier = item.is_a?(Numeric) ? 'rjust' : 'ljust'
|
58
|
+
cells << item.to_s.send(justifier, widths[i])
|
59
|
+
end
|
60
|
+
'| ' + cells.join(' | ') + ' |'
|
61
|
+
end
|
62
|
+
|
63
|
+
def build_footer(nrows, elapsed)
|
64
|
+
rows_label = nrows == 1 ? 'row' : 'rows'
|
65
|
+
"#{nrows} #{rows_label} in set (%.2f sec)" % elapsed
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module MySQL
|
4
|
+
module Quoting # :nodoc:
|
5
|
+
QUOTED_TRUE, QUOTED_FALSE = '1', '0'
|
6
|
+
|
7
|
+
def quote_column_name(name)
|
8
|
+
@quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`"
|
9
|
+
end
|
10
|
+
|
11
|
+
def quote_table_name(name)
|
12
|
+
@quoted_table_names[name] ||= super.gsub('.', '`.`')
|
13
|
+
end
|
14
|
+
|
15
|
+
def quoted_true
|
16
|
+
QUOTED_TRUE
|
17
|
+
end
|
18
|
+
|
19
|
+
def unquoted_true
|
20
|
+
1
|
21
|
+
end
|
22
|
+
|
23
|
+
def quoted_false
|
24
|
+
QUOTED_FALSE
|
25
|
+
end
|
26
|
+
|
27
|
+
def unquoted_false
|
28
|
+
0
|
29
|
+
end
|
30
|
+
|
31
|
+
def quoted_date(value)
|
32
|
+
if supports_datetime_with_precision?
|
33
|
+
super
|
34
|
+
else
|
35
|
+
super.sub(/\.\d{6}\z/, '')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def _quote(value)
|
42
|
+
if value.is_a?(Type::Binary::Data)
|
43
|
+
"x'#{value.hex}'"
|
44
|
+
else
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module MySQL
|
4
|
+
class SchemaCreation < AbstractAdapter::SchemaCreation
|
5
|
+
delegate :add_sql_comment!, to: :@conn
|
6
|
+
private :add_sql_comment!
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def visit_DropForeignKey(name)
|
11
|
+
"DROP FOREIGN KEY #{name}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def visit_ColumnDefinition(o)
|
15
|
+
o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale, o.unsigned)
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def visit_AddColumnDefinition(o)
|
20
|
+
add_column_position!(super, column_options(o.column))
|
21
|
+
end
|
22
|
+
|
23
|
+
def visit_ChangeColumnDefinition(o)
|
24
|
+
change_column_sql = "CHANGE #{quote_column_name(o.name)} #{accept(o.column)}"
|
25
|
+
add_column_position!(change_column_sql, column_options(o.column))
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_table_options!(create_sql, options)
|
29
|
+
add_sql_comment!(super, options[:comment])
|
30
|
+
end
|
31
|
+
|
32
|
+
def column_options(o)
|
33
|
+
column_options = super
|
34
|
+
column_options[:charset] = o.charset
|
35
|
+
column_options
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_column_options!(sql, options)
|
39
|
+
if charset = options[:charset]
|
40
|
+
sql << " CHARACTER SET #{charset}"
|
41
|
+
end
|
42
|
+
|
43
|
+
if collation = options[:collation]
|
44
|
+
sql << " COLLATE #{collation}"
|
45
|
+
end
|
46
|
+
|
47
|
+
add_sql_comment!(super, options[:comment])
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_column_position!(sql, options)
|
51
|
+
if options[:first]
|
52
|
+
sql << " FIRST"
|
53
|
+
elsif options[:after]
|
54
|
+
sql << " AFTER #{quote_column_name(options[:after])}"
|
55
|
+
end
|
56
|
+
|
57
|
+
sql
|
58
|
+
end
|
59
|
+
|
60
|
+
def index_in_create(table_name, column_name, options)
|
61
|
+
index_name, index_type, index_columns, _, _, index_using, comment = @conn.add_index_options(table_name, column_name, options)
|
62
|
+
add_sql_comment!("#{index_type} INDEX #{quote_column_name(index_name)} #{index_using} (#{index_columns})", comment)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module MySQL
|
4
|
+
module ColumnMethods
|
5
|
+
def primary_key(name, type = :primary_key, **options)
|
6
|
+
options[:auto_increment] = true if type == :bigint && !options.key?(:default)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def blob(*args, **options)
|
11
|
+
args.each { |name| column(name, :blob, options) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def tinyblob(*args, **options)
|
15
|
+
args.each { |name| column(name, :tinyblob, options) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def mediumblob(*args, **options)
|
19
|
+
args.each { |name| column(name, :mediumblob, options) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def longblob(*args, **options)
|
23
|
+
args.each { |name| column(name, :longblob, options) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def tinytext(*args, **options)
|
27
|
+
args.each { |name| column(name, :tinytext, options) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def mediumtext(*args, **options)
|
31
|
+
args.each { |name| column(name, :mediumtext, options) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def longtext(*args, **options)
|
35
|
+
args.each { |name| column(name, :longtext, options) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def json(*args, **options)
|
39
|
+
args.each { |name| column(name, :json, options) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def unsigned_integer(*args, **options)
|
43
|
+
args.each { |name| column(name, :unsigned_integer, options) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def unsigned_bigint(*args, **options)
|
47
|
+
args.each { |name| column(name, :unsigned_bigint, options) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def unsigned_float(*args, **options)
|
51
|
+
args.each { |name| column(name, :unsigned_float, options) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def unsigned_decimal(*args, **options)
|
55
|
+
args.each { |name| column(name, :unsigned_decimal, options) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class ColumnDefinition < ActiveRecord::ConnectionAdapters::ColumnDefinition
|
60
|
+
attr_accessor :charset, :unsigned
|
61
|
+
end
|
62
|
+
|
63
|
+
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
64
|
+
include ColumnMethods
|
65
|
+
|
66
|
+
def new_column_definition(name, type, options) # :nodoc:
|
67
|
+
column = super
|
68
|
+
case column.type
|
69
|
+
when :primary_key
|
70
|
+
column.type = :integer
|
71
|
+
column.auto_increment = true
|
72
|
+
when /\Aunsigned_(?<type>.+)\z/
|
73
|
+
column.type = $~[:type].to_sym
|
74
|
+
column.unsigned = true
|
75
|
+
end
|
76
|
+
column.unsigned ||= options[:unsigned]
|
77
|
+
column.charset = options[:charset]
|
78
|
+
column
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def create_column_definition(name, type)
|
84
|
+
MySQL::ColumnDefinition.new(name, type)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class Table < ActiveRecord::ConnectionAdapters::Table
|
89
|
+
include ColumnMethods
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|