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.

Files changed (264) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1715 -604
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +40 -45
  5. data/examples/performance.rb +33 -22
  6. data/examples/simple.rb +3 -4
  7. data/lib/active_record/aggregations.rb +76 -51
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +54 -40
  10. data/lib/active_record/associations/association.rb +76 -56
  11. data/lib/active_record/associations/association_scope.rb +125 -93
  12. data/lib/active_record/associations/belongs_to_association.rb +57 -28
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  14. data/lib/active_record/associations/builder/association.rb +120 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +115 -62
  16. data/lib/active_record/associations/builder/collection_association.rb +61 -53
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +117 -43
  18. data/lib/active_record/associations/builder/has_many.rb +9 -65
  19. data/lib/active_record/associations/builder/has_one.rb +18 -52
  20. data/lib/active_record/associations/builder/singular_association.rb +18 -19
  21. data/lib/active_record/associations/collection_association.rb +268 -186
  22. data/lib/active_record/associations/collection_proxy.rb +1003 -63
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +81 -41
  25. data/lib/active_record/associations/has_many_through_association.rb +76 -55
  26. data/lib/active_record/associations/has_one_association.rb +51 -21
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +83 -108
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +239 -155
  32. data/lib/active_record/associations/preloader/association.rb +97 -62
  33. data/lib/active_record/associations/preloader/collection_association.rb +2 -8
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +75 -33
  38. data/lib/active_record/associations/preloader.rb +111 -79
  39. data/lib/active_record/associations/singular_association.rb +35 -13
  40. data/lib/active_record/associations/through_association.rb +41 -19
  41. data/lib/active_record/associations.rb +727 -501
  42. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  43. data/lib/active_record/attribute.rb +213 -0
  44. data/lib/active_record/attribute_assignment.rb +32 -162
  45. data/lib/active_record/attribute_decorators.rb +67 -0
  46. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  47. data/lib/active_record/attribute_methods/dirty.rb +101 -61
  48. data/lib/active_record/attribute_methods/primary_key.rb +50 -36
  49. data/lib/active_record/attribute_methods/query.rb +7 -6
  50. data/lib/active_record/attribute_methods/read.rb +56 -117
  51. data/lib/active_record/attribute_methods/serialization.rb +43 -96
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +93 -42
  53. data/lib/active_record/attribute_methods/write.rb +34 -45
  54. data/lib/active_record/attribute_methods.rb +333 -144
  55. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  56. data/lib/active_record/attribute_set/builder.rb +108 -0
  57. data/lib/active_record/attribute_set.rb +108 -0
  58. data/lib/active_record/attributes.rb +265 -0
  59. data/lib/active_record/autosave_association.rb +285 -223
  60. data/lib/active_record/base.rb +95 -490
  61. data/lib/active_record/callbacks.rb +95 -61
  62. data/lib/active_record/coders/json.rb +13 -0
  63. data/lib/active_record/coders/yaml_column.rb +28 -19
  64. data/lib/active_record/collection_cache_key.rb +40 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +724 -277
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -192
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -26
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +140 -57
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +147 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +419 -276
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +105 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +963 -276
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +232 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +397 -106
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +643 -342
  78. data/lib/active_record/connection_adapters/column.rb +30 -259
  79. data/lib/active_record/connection_adapters/connection_specification.rb +263 -0
  80. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  81. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  82. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  83. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  84. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  86. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  87. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  88. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  89. data/lib/active_record/connection_adapters/mysql2_adapter.rb +47 -196
  90. data/lib/active_record/connection_adapters/postgresql/column.rb +15 -0
  91. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +170 -0
  92. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +70 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +48 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +21 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +10 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +39 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +93 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  112. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  113. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  114. data/lib/active_record/connection_adapters/postgresql/oid.rb +31 -0
  115. data/lib/active_record/connection_adapters/postgresql/quoting.rb +116 -0
  116. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +49 -0
  117. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +180 -0
  118. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  119. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +682 -0
  120. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  121. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  122. data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -1039
  123. data/lib/active_record/connection_adapters/schema_cache.rb +74 -36
  124. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  125. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +538 -24
  129. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  130. data/lib/active_record/connection_handling.rb +155 -0
  131. data/lib/active_record/core.rb +561 -0
  132. data/lib/active_record/counter_cache.rb +146 -105
  133. data/lib/active_record/dynamic_matchers.rb +101 -64
  134. data/lib/active_record/enum.rb +234 -0
  135. data/lib/active_record/errors.rb +153 -56
  136. data/lib/active_record/explain.rb +15 -63
  137. data/lib/active_record/explain_registry.rb +30 -0
  138. data/lib/active_record/explain_subscriber.rb +10 -6
  139. data/lib/active_record/fixture_set/file.rb +77 -0
  140. data/lib/active_record/fixtures.rb +355 -232
  141. data/lib/active_record/gem_version.rb +15 -0
  142. data/lib/active_record/inheritance.rb +144 -79
  143. data/lib/active_record/integration.rb +66 -13
  144. data/lib/active_record/internal_metadata.rb +56 -0
  145. data/lib/active_record/legacy_yaml_adapter.rb +46 -0
  146. data/lib/active_record/locale/en.yml +9 -1
  147. data/lib/active_record/locking/optimistic.rb +77 -56
  148. data/lib/active_record/locking/pessimistic.rb +6 -6
  149. data/lib/active_record/log_subscriber.rb +53 -28
  150. data/lib/active_record/migration/command_recorder.rb +166 -33
  151. data/lib/active_record/migration/compatibility.rb +126 -0
  152. data/lib/active_record/migration/join_table.rb +15 -0
  153. data/lib/active_record/migration.rb +792 -264
  154. data/lib/active_record/model_schema.rb +192 -130
  155. data/lib/active_record/nested_attributes.rb +238 -145
  156. data/lib/active_record/no_touching.rb +52 -0
  157. data/lib/active_record/null_relation.rb +89 -0
  158. data/lib/active_record/persistence.rb +357 -157
  159. data/lib/active_record/query_cache.rb +22 -43
  160. data/lib/active_record/querying.rb +34 -23
  161. data/lib/active_record/railtie.rb +88 -48
  162. data/lib/active_record/railties/console_sandbox.rb +3 -4
  163. data/lib/active_record/railties/controller_runtime.rb +5 -4
  164. data/lib/active_record/railties/databases.rake +170 -422
  165. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  166. data/lib/active_record/readonly_attributes.rb +2 -5
  167. data/lib/active_record/reflection.rb +715 -189
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  169. data/lib/active_record/relation/batches.rb +203 -50
  170. data/lib/active_record/relation/calculations.rb +203 -194
  171. data/lib/active_record/relation/delegation.rb +103 -25
  172. data/lib/active_record/relation/finder_methods.rb +457 -261
  173. data/lib/active_record/relation/from_clause.rb +32 -0
  174. data/lib/active_record/relation/merger.rb +167 -0
  175. data/lib/active_record/relation/predicate_builder/array_handler.rb +43 -0
  176. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  177. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  179. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  180. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  181. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  182. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  183. data/lib/active_record/relation/predicate_builder.rb +153 -48
  184. data/lib/active_record/relation/query_attribute.rb +19 -0
  185. data/lib/active_record/relation/query_methods.rb +1019 -194
  186. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  187. data/lib/active_record/relation/spawn_methods.rb +46 -150
  188. data/lib/active_record/relation/where_clause.rb +174 -0
  189. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  190. data/lib/active_record/relation.rb +450 -245
  191. data/lib/active_record/result.rb +104 -12
  192. data/lib/active_record/runtime_registry.rb +22 -0
  193. data/lib/active_record/sanitization.rb +120 -94
  194. data/lib/active_record/schema.rb +28 -18
  195. data/lib/active_record/schema_dumper.rb +141 -74
  196. data/lib/active_record/schema_migration.rb +50 -0
  197. data/lib/active_record/scoping/default.rb +64 -57
  198. data/lib/active_record/scoping/named.rb +93 -108
  199. data/lib/active_record/scoping.rb +73 -121
  200. data/lib/active_record/secure_token.rb +38 -0
  201. data/lib/active_record/serialization.rb +7 -5
  202. data/lib/active_record/statement_cache.rb +113 -0
  203. data/lib/active_record/store.rb +173 -15
  204. data/lib/active_record/suppressor.rb +58 -0
  205. data/lib/active_record/table_metadata.rb +68 -0
  206. data/lib/active_record/tasks/database_tasks.rb +313 -0
  207. data/lib/active_record/tasks/mysql_database_tasks.rb +151 -0
  208. data/lib/active_record/tasks/postgresql_database_tasks.rb +110 -0
  209. data/lib/active_record/tasks/sqlite_database_tasks.rb +59 -0
  210. data/lib/active_record/timestamp.rb +42 -24
  211. data/lib/active_record/touch_later.rb +58 -0
  212. data/lib/active_record/transactions.rb +233 -105
  213. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  214. data/lib/active_record/type/date.rb +7 -0
  215. data/lib/active_record/type/date_time.rb +7 -0
  216. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  217. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  218. data/lib/active_record/type/internal/timezone.rb +15 -0
  219. data/lib/active_record/type/serialized.rb +63 -0
  220. data/lib/active_record/type/time.rb +20 -0
  221. data/lib/active_record/type/type_map.rb +64 -0
  222. data/lib/active_record/type.rb +72 -0
  223. data/lib/active_record/type_caster/connection.rb +29 -0
  224. data/lib/active_record/type_caster/map.rb +19 -0
  225. data/lib/active_record/type_caster.rb +7 -0
  226. data/lib/active_record/validations/absence.rb +23 -0
  227. data/lib/active_record/validations/associated.rb +33 -18
  228. data/lib/active_record/validations/length.rb +24 -0
  229. data/lib/active_record/validations/presence.rb +66 -0
  230. data/lib/active_record/validations/uniqueness.rb +128 -68
  231. data/lib/active_record/validations.rb +48 -40
  232. data/lib/active_record/version.rb +5 -7
  233. data/lib/active_record.rb +71 -47
  234. data/lib/rails/generators/active_record/migration/migration_generator.rb +56 -8
  235. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +24 -0
  236. data/lib/rails/generators/active_record/migration/templates/migration.rb +28 -16
  237. data/lib/rails/generators/active_record/migration.rb +18 -8
  238. data/lib/rails/generators/active_record/model/model_generator.rb +38 -16
  239. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  240. data/lib/rails/generators/active_record/model/templates/model.rb +7 -6
  241. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  242. data/lib/rails/generators/active_record.rb +3 -11
  243. metadata +188 -134
  244. data/examples/associations.png +0 -0
  245. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  246. data/lib/active_record/associations/join_helper.rb +0 -55
  247. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  248. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  249. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  250. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
  251. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  252. data/lib/active_record/dynamic_finder_match.rb +0 -68
  253. data/lib/active_record/dynamic_scope_match.rb +0 -23
  254. data/lib/active_record/fixtures/file.rb +0 -65
  255. data/lib/active_record/identity_map.rb +0 -162
  256. data/lib/active_record/observer.rb +0 -121
  257. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  258. data/lib/active_record/session_store.rb +0 -360
  259. data/lib/active_record/test_case.rb +0 -73
  260. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  261. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  262. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  263. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  264. 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
- case value
13
- when String, ActiveSupport::Multibyte::Chars
14
- value = value.to_s
15
- return "'#{quote_string(value)}'" unless column
16
-
17
- case column.type
18
- when :binary then "'#{quote_string(column.string_to_binary(value))}'"
19
- when :integer then value.to_i.to_s
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
- return value.id if value.respond_to?(:quoted_id)
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
- case value
49
- when String, ActiveSupport::Multibyte::Chars
50
- value = value.to_s
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
- when true, false
62
- if column && column.type == :integer
63
- value ? 1 : 0
64
- else
65
- value ? 't' : 'f'
66
- end
67
- # BigDecimals need to be put in a non-normalized form and quoted.
68
- when nil then nil
69
- when BigDecimal then value.to_s('F')
70
- when Numeric then value
71
- when Date, Time then quoted_date(value)
72
- when Symbol then value.to_s
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
- YAML.dump(value)
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(/\\/, '\&\&').gsub(/'/, "''") # ' (for ruby-mode)
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