activerecord 3.2.19 → 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 +7 -0
- data/CHANGELOG.md +1715 -604
- data/MIT-LICENSE +2 -2
- data/README.rdoc +40 -45
- data/examples/performance.rb +33 -22
- data/examples/simple.rb +3 -4
- data/lib/active_record/aggregations.rb +76 -51
- data/lib/active_record/association_relation.rb +35 -0
- data/lib/active_record/associations/alias_tracker.rb +54 -40
- data/lib/active_record/associations/association.rb +76 -56
- data/lib/active_record/associations/association_scope.rb +125 -93
- data/lib/active_record/associations/belongs_to_association.rb +57 -28
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
- data/lib/active_record/associations/builder/association.rb +120 -32
- data/lib/active_record/associations/builder/belongs_to.rb +115 -62
- data/lib/active_record/associations/builder/collection_association.rb +61 -53
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +117 -43
- data/lib/active_record/associations/builder/has_many.rb +9 -65
- data/lib/active_record/associations/builder/has_one.rb +18 -52
- data/lib/active_record/associations/builder/singular_association.rb +18 -19
- data/lib/active_record/associations/collection_association.rb +268 -186
- data/lib/active_record/associations/collection_proxy.rb +1003 -63
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +81 -41
- data/lib/active_record/associations/has_many_through_association.rb +76 -55
- data/lib/active_record/associations/has_one_association.rb +51 -21
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +83 -108
- data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
- data/lib/active_record/associations/join_dependency.rb +239 -155
- data/lib/active_record/associations/preloader/association.rb +97 -62
- data/lib/active_record/associations/preloader/collection_association.rb +2 -8
- data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +75 -33
- data/lib/active_record/associations/preloader.rb +111 -79
- data/lib/active_record/associations/singular_association.rb +35 -13
- data/lib/active_record/associations/through_association.rb +41 -19
- data/lib/active_record/associations.rb +727 -501
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +213 -0
- data/lib/active_record/attribute_assignment.rb +32 -162
- data/lib/active_record/attribute_decorators.rb +67 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -61
- data/lib/active_record/attribute_methods/primary_key.rb +50 -36
- data/lib/active_record/attribute_methods/query.rb +7 -6
- data/lib/active_record/attribute_methods/read.rb +56 -117
- data/lib/active_record/attribute_methods/serialization.rb +43 -96
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +93 -42
- data/lib/active_record/attribute_methods/write.rb +34 -45
- data/lib/active_record/attribute_methods.rb +333 -144
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +108 -0
- data/lib/active_record/attribute_set.rb +108 -0
- data/lib/active_record/attributes.rb +265 -0
- data/lib/active_record/autosave_association.rb +285 -223
- data/lib/active_record/base.rb +95 -490
- data/lib/active_record/callbacks.rb +95 -61
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/coders/yaml_column.rb +28 -19
- data/lib/active_record/collection_cache_key.rb +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +724 -277
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -192
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -26
- data/lib/active_record/connection_adapters/abstract/quoting.rb +140 -57
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +147 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +419 -276
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +105 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +963 -276
- data/lib/active_record/connection_adapters/abstract/transaction.rb +232 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +397 -106
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +643 -342
- data/lib/active_record/connection_adapters/column.rb +30 -259
- data/lib/active_record/connection_adapters/connection_specification.rb +263 -0
- 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 +47 -196
- data/lib/active_record/connection_adapters/postgresql/column.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +170 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +70 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +48 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- 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 +93 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +31 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +116 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +180 -0
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +682 -0
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -1039
- data/lib/active_record/connection_adapters/schema_cache.rb +74 -36
- 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 +538 -24
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +155 -0
- data/lib/active_record/core.rb +561 -0
- data/lib/active_record/counter_cache.rb +146 -105
- data/lib/active_record/dynamic_matchers.rb +101 -64
- data/lib/active_record/enum.rb +234 -0
- data/lib/active_record/errors.rb +153 -56
- data/lib/active_record/explain.rb +15 -63
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +10 -6
- data/lib/active_record/fixture_set/file.rb +77 -0
- data/lib/active_record/fixtures.rb +355 -232
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +144 -79
- data/lib/active_record/integration.rb +66 -13
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +46 -0
- data/lib/active_record/locale/en.yml +9 -1
- data/lib/active_record/locking/optimistic.rb +77 -56
- data/lib/active_record/locking/pessimistic.rb +6 -6
- data/lib/active_record/log_subscriber.rb +53 -28
- data/lib/active_record/migration/command_recorder.rb +166 -33
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +792 -264
- data/lib/active_record/model_schema.rb +192 -130
- data/lib/active_record/nested_attributes.rb +238 -145
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +89 -0
- data/lib/active_record/persistence.rb +357 -157
- data/lib/active_record/query_cache.rb +22 -43
- data/lib/active_record/querying.rb +34 -23
- data/lib/active_record/railtie.rb +88 -48
- data/lib/active_record/railties/console_sandbox.rb +3 -4
- data/lib/active_record/railties/controller_runtime.rb +5 -4
- data/lib/active_record/railties/databases.rake +170 -422
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -5
- data/lib/active_record/reflection.rb +715 -189
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +203 -50
- data/lib/active_record/relation/calculations.rb +203 -194
- data/lib/active_record/relation/delegation.rb +103 -25
- data/lib/active_record/relation/finder_methods.rb +457 -261
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +167 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +43 -0
- 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 +13 -0
- data/lib/active_record/relation/predicate_builder.rb +153 -48
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +1019 -194
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +46 -150
- 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 +450 -245
- data/lib/active_record/result.rb +104 -12
- data/lib/active_record/runtime_registry.rb +22 -0
- data/lib/active_record/sanitization.rb +120 -94
- data/lib/active_record/schema.rb +28 -18
- data/lib/active_record/schema_dumper.rb +141 -74
- data/lib/active_record/schema_migration.rb +50 -0
- data/lib/active_record/scoping/default.rb +64 -57
- data/lib/active_record/scoping/named.rb +93 -108
- data/lib/active_record/scoping.rb +73 -121
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +7 -5
- data/lib/active_record/statement_cache.rb +113 -0
- data/lib/active_record/store.rb +173 -15
- 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 +313 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +151 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +110 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +59 -0
- data/lib/active_record/timestamp.rb +42 -24
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +233 -105
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +7 -0
- data/lib/active_record/type/date_time.rb +7 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- 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 +63 -0
- data/lib/active_record/type/time.rb +20 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type.rb +72 -0
- 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 +33 -18
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +66 -0
- data/lib/active_record/validations/uniqueness.rb +128 -68
- data/lib/active_record/validations.rb +48 -40
- data/lib/active_record/version.rb +5 -7
- data/lib/active_record.rb +71 -47
- data/lib/rails/generators/active_record/migration/migration_generator.rb +56 -8
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +24 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +28 -16
- data/lib/rails/generators/active_record/migration.rb +18 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -16
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +7 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- data/lib/rails/generators/active_record.rb +3 -11
- metadata +188 -134
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
- data/lib/active_record/associations/join_helper.rb +0 -55
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/serializers/xml_serializer.rb +0 -203
- data/lib/active_record/session_store.rb +0 -360
- data/lib/active_record/test_case.rb +0 -73
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -9,81 +9,80 @@ module ActiveRecord
|
|
9
9
|
# records are quoted as their primary key
|
10
10
|
return value.quoted_id if value.respond_to?(:quoted_id)
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
when :float then value.to_f.to_s
|
21
|
-
else
|
22
|
-
"'#{quote_string(value)}'"
|
23
|
-
end
|
24
|
-
|
25
|
-
when true, false
|
26
|
-
if column && column.type == :integer
|
27
|
-
value ? '1' : '0'
|
28
|
-
else
|
29
|
-
value ? quoted_true : quoted_false
|
30
|
-
end
|
31
|
-
# BigDecimals need to be put in a non-normalized form and quoted.
|
32
|
-
when nil then "NULL"
|
33
|
-
when BigDecimal then value.to_s('F')
|
34
|
-
when Numeric then value.to_s
|
35
|
-
when Date, Time then "'#{quoted_date(value)}'"
|
36
|
-
when Symbol then "'#{quote_string(value.to_s)}'"
|
37
|
-
else
|
38
|
-
"'#{quote_string(YAML.dump(value))}'"
|
12
|
+
if column
|
13
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
14
|
+
Passing a column to `quote` has been deprecated. It is only used
|
15
|
+
for type casting, which should be handled elsewhere. See
|
16
|
+
https://github.com/rails/arel/commit/6160bfbda1d1781c3b08a33ec4955f170e95be11
|
17
|
+
for more information.
|
18
|
+
MSG
|
19
|
+
value = type_cast_from_column(column, value)
|
39
20
|
end
|
21
|
+
|
22
|
+
_quote(value)
|
40
23
|
end
|
41
24
|
|
42
25
|
# Cast a +value+ to a type that the database understands. For example,
|
43
26
|
# SQLite does not understand dates, so this method will convert a Date
|
44
27
|
# to a String.
|
45
|
-
def type_cast(value, column)
|
46
|
-
|
28
|
+
def type_cast(value, column = nil)
|
29
|
+
if value.respond_to?(:quoted_id) && value.respond_to?(:id)
|
30
|
+
return value.id
|
31
|
+
end
|
47
32
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
return value unless column
|
52
|
-
|
53
|
-
case column.type
|
54
|
-
when :binary then value
|
55
|
-
when :integer then value.to_i
|
56
|
-
when :float then value.to_f
|
57
|
-
else
|
58
|
-
value
|
59
|
-
end
|
33
|
+
if column
|
34
|
+
value = type_cast_from_column(column, value)
|
35
|
+
end
|
60
36
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
37
|
+
_type_cast(value)
|
38
|
+
rescue TypeError
|
39
|
+
to_type = column ? " to #{column.type}" : ""
|
40
|
+
raise TypeError, "can't cast #{value.class}#{to_type}"
|
41
|
+
end
|
42
|
+
|
43
|
+
# If you are having to call this function, you are likely doing something
|
44
|
+
# wrong. The column does not have sufficient type information if the user
|
45
|
+
# provided a custom type on the class level either explicitly (via
|
46
|
+
# Attributes::ClassMethods#attribute) or implicitly (via
|
47
|
+
# AttributeMethods::Serialization::ClassMethods#serialize, +time_zone_aware_attributes+).
|
48
|
+
# In almost all cases, the sql type should only be used to change quoting behavior, when the primitive to
|
49
|
+
# represent the type doesn't sufficiently reflect the differences
|
50
|
+
# (varchar vs binary) for example. The type used to get this primitive
|
51
|
+
# should have been provided before reaching the connection adapter.
|
52
|
+
def type_cast_from_column(column, value) # :nodoc:
|
53
|
+
if column
|
54
|
+
type = lookup_cast_type_from_column(column)
|
55
|
+
type.serialize(value)
|
73
56
|
else
|
74
|
-
|
57
|
+
value
|
75
58
|
end
|
76
59
|
end
|
77
60
|
|
61
|
+
# See docs for #type_cast_from_column
|
62
|
+
def lookup_cast_type_from_column(column) # :nodoc:
|
63
|
+
lookup_cast_type(column.sql_type)
|
64
|
+
end
|
65
|
+
|
66
|
+
def fetch_type_metadata(sql_type)
|
67
|
+
cast_type = lookup_cast_type(sql_type)
|
68
|
+
SqlTypeMetadata.new(
|
69
|
+
sql_type: sql_type,
|
70
|
+
type: cast_type.type,
|
71
|
+
limit: cast_type.limit,
|
72
|
+
precision: cast_type.precision,
|
73
|
+
scale: cast_type.scale,
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
78
77
|
# Quotes a string, escaping any ' (single quote) and \ (backslash)
|
79
78
|
# characters.
|
80
79
|
def quote_string(s)
|
81
|
-
s.gsub(
|
80
|
+
s.gsub('\\'.freeze, '\&\&'.freeze).gsub("'".freeze, "''".freeze) # ' (for ruby-mode)
|
82
81
|
end
|
83
82
|
|
84
83
|
# Quotes the column name. Defaults to no quoting.
|
85
84
|
def quote_column_name(column_name)
|
86
|
-
column_name
|
85
|
+
column_name.to_s
|
87
86
|
end
|
88
87
|
|
89
88
|
# Quotes the table name. Defaults to column name quoting.
|
@@ -91,14 +90,45 @@ module ActiveRecord
|
|
91
90
|
quote_column_name(table_name)
|
92
91
|
end
|
93
92
|
|
93
|
+
# Override to return the quoted table name for assignment. Defaults to
|
94
|
+
# table quoting.
|
95
|
+
#
|
96
|
+
# This works for mysql2 where table.column can be used to
|
97
|
+
# resolve ambiguity.
|
98
|
+
#
|
99
|
+
# We override this in the sqlite3 and postgresql adapters to use only
|
100
|
+
# the column name (as per syntax requirements).
|
101
|
+
def quote_table_name_for_assignment(table, attr)
|
102
|
+
quote_table_name("#{table}.#{attr}")
|
103
|
+
end
|
104
|
+
|
105
|
+
def quote_default_expression(value, column) # :nodoc:
|
106
|
+
if value.is_a?(Proc)
|
107
|
+
value.call
|
108
|
+
else
|
109
|
+
value = lookup_cast_type(column.sql_type).serialize(value)
|
110
|
+
quote(value)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
94
114
|
def quoted_true
|
95
115
|
"'t'"
|
96
116
|
end
|
97
117
|
|
118
|
+
def unquoted_true
|
119
|
+
't'
|
120
|
+
end
|
121
|
+
|
98
122
|
def quoted_false
|
99
123
|
"'f'"
|
100
124
|
end
|
101
125
|
|
126
|
+
def unquoted_false
|
127
|
+
'f'
|
128
|
+
end
|
129
|
+
|
130
|
+
# Quote date/time values for use in SQL input. Includes microseconds
|
131
|
+
# if the value is a Time responding to usec.
|
102
132
|
def quoted_date(value)
|
103
133
|
if value.acts_like?(:time)
|
104
134
|
zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
|
@@ -108,7 +138,60 @@ module ActiveRecord
|
|
108
138
|
end
|
109
139
|
end
|
110
140
|
|
111
|
-
value.to_s(:db)
|
141
|
+
result = value.to_s(:db)
|
142
|
+
if value.respond_to?(:usec) && value.usec > 0
|
143
|
+
"#{result}.#{sprintf("%06d", value.usec)}"
|
144
|
+
else
|
145
|
+
result
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def quoted_time(value) # :nodoc:
|
150
|
+
quoted_date(value).sub(/\A2000-01-01 /, '')
|
151
|
+
end
|
152
|
+
|
153
|
+
def prepare_binds_for_database(binds) # :nodoc:
|
154
|
+
binds.map(&:value_for_database)
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
|
159
|
+
def types_which_need_no_typecasting
|
160
|
+
[nil, Numeric, String]
|
161
|
+
end
|
162
|
+
|
163
|
+
def _quote(value)
|
164
|
+
case value
|
165
|
+
when String, ActiveSupport::Multibyte::Chars, Type::Binary::Data
|
166
|
+
"'#{quote_string(value.to_s)}'"
|
167
|
+
when true then quoted_true
|
168
|
+
when false then quoted_false
|
169
|
+
when nil then "NULL"
|
170
|
+
# BigDecimals need to be put in a non-normalized form and quoted.
|
171
|
+
when BigDecimal then value.to_s('F')
|
172
|
+
when Numeric, ActiveSupport::Duration then value.to_s
|
173
|
+
when Type::Time::Value then "'#{quoted_time(value)}'"
|
174
|
+
when Date, Time then "'#{quoted_date(value)}'"
|
175
|
+
when Symbol then "'#{quote_string(value.to_s)}'"
|
176
|
+
when Class then "'#{value}'"
|
177
|
+
else raise TypeError, "can't quote #{value.class.name}"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def _type_cast(value)
|
182
|
+
case value
|
183
|
+
when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
|
184
|
+
value.to_s
|
185
|
+
when true then unquoted_true
|
186
|
+
when false then unquoted_false
|
187
|
+
# BigDecimals need to be put in a non-normalized form and quoted.
|
188
|
+
when BigDecimal then value.to_s('F')
|
189
|
+
when Type::Time::Value then quoted_time(value)
|
190
|
+
when Date, Time then quoted_date(value)
|
191
|
+
when *types_which_need_no_typecasting
|
192
|
+
value
|
193
|
+
else raise TypeError
|
194
|
+
end
|
112
195
|
end
|
113
196
|
end
|
114
197
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Savepoints
|
4
|
+
def current_savepoint_name
|
5
|
+
current_transaction.savepoint_name
|
6
|
+
end
|
7
|
+
|
8
|
+
def create_savepoint(name = current_savepoint_name)
|
9
|
+
execute("SAVEPOINT #{name}")
|
10
|
+
end
|
11
|
+
|
12
|
+
def exec_rollback_to_savepoint(name = current_savepoint_name)
|
13
|
+
execute("ROLLBACK TO SAVEPOINT #{name}")
|
14
|
+
end
|
15
|
+
|
16
|
+
def release_savepoint(name = current_savepoint_name)
|
17
|
+
execute("RELEASE SAVEPOINT #{name}")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'active_support/core_ext/string/strip'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
class AbstractAdapter
|
6
|
+
class SchemaCreation # :nodoc:
|
7
|
+
def initialize(conn)
|
8
|
+
@conn = conn
|
9
|
+
@cache = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def accept(o)
|
13
|
+
m = @cache[o.class] ||= "visit_#{o.class.name.split('::').last}"
|
14
|
+
send m, o
|
15
|
+
end
|
16
|
+
|
17
|
+
delegate :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
|
18
|
+
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options, to: :@conn
|
19
|
+
private :quote_column_name, :quote_table_name, :quote_default_expression, :type_to_sql,
|
20
|
+
:options_include_default?, :supports_indexes_in_create?, :supports_foreign_keys?, :foreign_key_options
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def visit_AlterTable(o)
|
25
|
+
sql = "ALTER TABLE #{quote_table_name(o.name)} "
|
26
|
+
sql << o.adds.map { |col| accept col }.join(' ')
|
27
|
+
sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(' ')
|
28
|
+
sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(' ')
|
29
|
+
end
|
30
|
+
|
31
|
+
def visit_ColumnDefinition(o)
|
32
|
+
o.sql_type ||= type_to_sql(o.type, o.limit, o.precision, o.scale)
|
33
|
+
column_sql = "#{quote_column_name(o.name)} #{o.sql_type}"
|
34
|
+
add_column_options!(column_sql, column_options(o)) unless o.type == :primary_key
|
35
|
+
column_sql
|
36
|
+
end
|
37
|
+
|
38
|
+
def visit_AddColumnDefinition(o)
|
39
|
+
"ADD #{accept(o.column)}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def visit_TableDefinition(o)
|
43
|
+
create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE #{quote_table_name(o.name)} "
|
44
|
+
|
45
|
+
statements = o.columns.map { |c| accept c }
|
46
|
+
statements << accept(o.primary_keys) if o.primary_keys
|
47
|
+
|
48
|
+
if supports_indexes_in_create?
|
49
|
+
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
|
50
|
+
end
|
51
|
+
|
52
|
+
if supports_foreign_keys?
|
53
|
+
statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
|
54
|
+
end
|
55
|
+
|
56
|
+
create_sql << "(#{statements.join(', ')})" if statements.present?
|
57
|
+
add_table_options!(create_sql, table_options(o))
|
58
|
+
create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
|
59
|
+
create_sql
|
60
|
+
end
|
61
|
+
|
62
|
+
def visit_PrimaryKeyDefinition(o)
|
63
|
+
"PRIMARY KEY (#{o.name.join(', ')})"
|
64
|
+
end
|
65
|
+
|
66
|
+
def visit_ForeignKeyDefinition(o)
|
67
|
+
sql = <<-SQL.strip_heredoc
|
68
|
+
CONSTRAINT #{quote_column_name(o.name)}
|
69
|
+
FOREIGN KEY (#{quote_column_name(o.column)})
|
70
|
+
REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
|
71
|
+
SQL
|
72
|
+
sql << " #{action_sql('DELETE', o.on_delete)}" if o.on_delete
|
73
|
+
sql << " #{action_sql('UPDATE', o.on_update)}" if o.on_update
|
74
|
+
sql
|
75
|
+
end
|
76
|
+
|
77
|
+
def visit_AddForeignKey(o)
|
78
|
+
"ADD #{accept(o)}"
|
79
|
+
end
|
80
|
+
|
81
|
+
def visit_DropForeignKey(name)
|
82
|
+
"DROP CONSTRAINT #{quote_column_name(name)}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def table_options(o)
|
86
|
+
table_options = {}
|
87
|
+
table_options[:comment] = o.comment
|
88
|
+
table_options[:options] = o.options
|
89
|
+
table_options
|
90
|
+
end
|
91
|
+
|
92
|
+
def add_table_options!(create_sql, options)
|
93
|
+
if options_sql = options[:options]
|
94
|
+
create_sql << " #{options_sql}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def column_options(o)
|
99
|
+
column_options = {}
|
100
|
+
column_options[:null] = o.null unless o.null.nil?
|
101
|
+
column_options[:default] = o.default unless o.default.nil?
|
102
|
+
column_options[:column] = o
|
103
|
+
column_options[:first] = o.first
|
104
|
+
column_options[:after] = o.after
|
105
|
+
column_options[:auto_increment] = o.auto_increment
|
106
|
+
column_options[:primary_key] = o.primary_key
|
107
|
+
column_options[:collation] = o.collation
|
108
|
+
column_options[:comment] = o.comment
|
109
|
+
column_options
|
110
|
+
end
|
111
|
+
|
112
|
+
def add_column_options!(sql, options)
|
113
|
+
sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
|
114
|
+
# must explicitly check for :null to allow change_column to work on migrations
|
115
|
+
if options[:null] == false
|
116
|
+
sql << " NOT NULL"
|
117
|
+
end
|
118
|
+
if options[:auto_increment] == true
|
119
|
+
sql << " AUTO_INCREMENT"
|
120
|
+
end
|
121
|
+
if options[:primary_key] == true
|
122
|
+
sql << " PRIMARY KEY"
|
123
|
+
end
|
124
|
+
sql
|
125
|
+
end
|
126
|
+
|
127
|
+
def foreign_key_in_create(from_table, to_table, options)
|
128
|
+
options = foreign_key_options(from_table, to_table, options)
|
129
|
+
accept ForeignKeyDefinition.new(from_table, to_table, options)
|
130
|
+
end
|
131
|
+
|
132
|
+
def action_sql(action, dependency)
|
133
|
+
case dependency
|
134
|
+
when :nullify then "ON #{action} SET NULL"
|
135
|
+
when :cascade then "ON #{action} CASCADE"
|
136
|
+
when :restrict then "ON #{action} RESTRICT"
|
137
|
+
else
|
138
|
+
raise ArgumentError, <<-MSG.strip_heredoc
|
139
|
+
'#{dependency}' is not supported for :on_update or :on_delete.
|
140
|
+
Supported values are: :nullify, :cascade, :restrict
|
141
|
+
MSG
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|