activerecord 4.1.15 → 4.2.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (185) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1162 -1792
  3. data/README.rdoc +15 -10
  4. data/lib/active_record.rb +4 -0
  5. data/lib/active_record/aggregations.rb +15 -8
  6. data/lib/active_record/association_relation.rb +13 -0
  7. data/lib/active_record/associations.rb +158 -49
  8. data/lib/active_record/associations/alias_tracker.rb +3 -12
  9. data/lib/active_record/associations/association.rb +16 -4
  10. data/lib/active_record/associations/association_scope.rb +83 -38
  11. data/lib/active_record/associations/belongs_to_association.rb +28 -10
  12. data/lib/active_record/associations/builder/association.rb +15 -4
  13. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -1
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +8 -13
  16. data/lib/active_record/associations/builder/has_many.rb +1 -1
  17. data/lib/active_record/associations/builder/has_one.rb +2 -2
  18. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  19. data/lib/active_record/associations/collection_association.rb +63 -27
  20. data/lib/active_record/associations/collection_proxy.rb +29 -35
  21. data/lib/active_record/associations/foreign_association.rb +11 -0
  22. data/lib/active_record/associations/has_many_association.rb +83 -22
  23. data/lib/active_record/associations/has_many_through_association.rb +49 -26
  24. data/lib/active_record/associations/has_one_association.rb +1 -1
  25. data/lib/active_record/associations/join_dependency.rb +26 -13
  26. data/lib/active_record/associations/join_dependency/join_association.rb +25 -15
  27. data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
  28. data/lib/active_record/associations/preloader.rb +36 -26
  29. data/lib/active_record/associations/preloader/association.rb +14 -11
  30. data/lib/active_record/associations/preloader/through_association.rb +4 -3
  31. data/lib/active_record/associations/singular_association.rb +17 -2
  32. data/lib/active_record/associations/through_association.rb +5 -12
  33. data/lib/active_record/attribute.rb +163 -0
  34. data/lib/active_record/attribute_assignment.rb +19 -11
  35. data/lib/active_record/attribute_decorators.rb +66 -0
  36. data/lib/active_record/attribute_methods.rb +56 -94
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  38. data/lib/active_record/attribute_methods/dirty.rb +107 -43
  39. data/lib/active_record/attribute_methods/primary_key.rb +7 -8
  40. data/lib/active_record/attribute_methods/query.rb +1 -1
  41. data/lib/active_record/attribute_methods/read.rb +22 -59
  42. data/lib/active_record/attribute_methods/serialization.rb +16 -150
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -40
  44. data/lib/active_record/attribute_methods/write.rb +9 -24
  45. data/lib/active_record/attribute_set.rb +81 -0
  46. data/lib/active_record/attribute_set/builder.rb +106 -0
  47. data/lib/active_record/attributes.rb +147 -0
  48. data/lib/active_record/autosave_association.rb +19 -12
  49. data/lib/active_record/base.rb +13 -24
  50. data/lib/active_record/callbacks.rb +6 -6
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +84 -52
  52. data/lib/active_record/connection_adapters/abstract/database_statements.rb +52 -50
  53. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  54. data/lib/active_record/connection_adapters/abstract/quoting.rb +60 -60
  55. data/lib/active_record/connection_adapters/abstract/savepoints.rb +1 -1
  56. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +39 -4
  57. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +138 -56
  58. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +268 -71
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +125 -118
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +171 -59
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +293 -139
  63. data/lib/active_record/connection_adapters/column.rb +29 -240
  64. data/lib/active_record/connection_adapters/connection_specification.rb +15 -24
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
  66. data/lib/active_record/connection_adapters/mysql_adapter.rb +67 -144
  67. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  68. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  69. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +40 -25
  70. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
  71. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  96. data/lib/active_record/connection_adapters/postgresql/quoting.rb +46 -136
  97. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  99. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +131 -43
  100. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  101. data/lib/active_record/connection_adapters/postgresql_adapter.rb +224 -477
  102. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  103. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -75
  104. data/lib/active_record/connection_handling.rb +1 -1
  105. data/lib/active_record/core.rb +163 -39
  106. data/lib/active_record/counter_cache.rb +60 -6
  107. data/lib/active_record/enum.rb +9 -11
  108. data/lib/active_record/errors.rb +53 -30
  109. data/lib/active_record/explain.rb +1 -1
  110. data/lib/active_record/explain_subscriber.rb +1 -1
  111. data/lib/active_record/fixtures.rb +55 -69
  112. data/lib/active_record/gem_version.rb +4 -4
  113. data/lib/active_record/inheritance.rb +35 -10
  114. data/lib/active_record/integration.rb +4 -4
  115. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  116. data/lib/active_record/locking/optimistic.rb +46 -26
  117. data/lib/active_record/migration.rb +71 -46
  118. data/lib/active_record/migration/command_recorder.rb +19 -2
  119. data/lib/active_record/migration/join_table.rb +1 -1
  120. data/lib/active_record/model_schema.rb +52 -58
  121. data/lib/active_record/nested_attributes.rb +5 -5
  122. data/lib/active_record/no_touching.rb +1 -1
  123. data/lib/active_record/persistence.rb +46 -26
  124. data/lib/active_record/query_cache.rb +3 -3
  125. data/lib/active_record/querying.rb +10 -7
  126. data/lib/active_record/railtie.rb +18 -11
  127. data/lib/active_record/railties/databases.rake +50 -51
  128. data/lib/active_record/readonly_attributes.rb +0 -1
  129. data/lib/active_record/reflection.rb +273 -114
  130. data/lib/active_record/relation.rb +57 -25
  131. data/lib/active_record/relation/batches.rb +0 -2
  132. data/lib/active_record/relation/calculations.rb +41 -37
  133. data/lib/active_record/relation/finder_methods.rb +70 -47
  134. data/lib/active_record/relation/merger.rb +39 -29
  135. data/lib/active_record/relation/predicate_builder.rb +16 -8
  136. data/lib/active_record/relation/predicate_builder/array_handler.rb +32 -13
  137. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -5
  138. data/lib/active_record/relation/query_methods.rb +114 -65
  139. data/lib/active_record/relation/spawn_methods.rb +3 -0
  140. data/lib/active_record/result.rb +18 -7
  141. data/lib/active_record/sanitization.rb +12 -2
  142. data/lib/active_record/schema.rb +0 -1
  143. data/lib/active_record/schema_dumper.rb +59 -28
  144. data/lib/active_record/schema_migration.rb +5 -4
  145. data/lib/active_record/scoping/default.rb +6 -4
  146. data/lib/active_record/scoping/named.rb +4 -0
  147. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  148. data/lib/active_record/statement_cache.rb +95 -10
  149. data/lib/active_record/store.rb +5 -5
  150. data/lib/active_record/tasks/database_tasks.rb +61 -6
  151. data/lib/active_record/tasks/mysql_database_tasks.rb +32 -17
  152. data/lib/active_record/tasks/postgresql_database_tasks.rb +20 -9
  153. data/lib/active_record/timestamp.rb +9 -7
  154. data/lib/active_record/transactions.rb +53 -27
  155. data/lib/active_record/type.rb +23 -0
  156. data/lib/active_record/type/big_integer.rb +13 -0
  157. data/lib/active_record/type/binary.rb +50 -0
  158. data/lib/active_record/type/boolean.rb +31 -0
  159. data/lib/active_record/type/date.rb +50 -0
  160. data/lib/active_record/type/date_time.rb +54 -0
  161. data/lib/active_record/type/decimal.rb +64 -0
  162. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  163. data/lib/active_record/type/decorator.rb +14 -0
  164. data/lib/active_record/type/float.rb +19 -0
  165. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  166. data/lib/active_record/type/integer.rb +59 -0
  167. data/lib/active_record/type/mutable.rb +16 -0
  168. data/lib/active_record/type/numeric.rb +36 -0
  169. data/lib/active_record/type/serialized.rb +62 -0
  170. data/lib/active_record/type/string.rb +40 -0
  171. data/lib/active_record/type/text.rb +11 -0
  172. data/lib/active_record/type/time.rb +26 -0
  173. data/lib/active_record/type/time_value.rb +38 -0
  174. data/lib/active_record/type/type_map.rb +64 -0
  175. data/lib/active_record/type/unsigned_integer.rb +15 -0
  176. data/lib/active_record/type/value.rb +110 -0
  177. data/lib/active_record/validations.rb +25 -19
  178. data/lib/active_record/validations/associated.rb +5 -3
  179. data/lib/active_record/validations/presence.rb +5 -3
  180. data/lib/active_record/validations/uniqueness.rb +25 -29
  181. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  182. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  183. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  184. metadata +66 -11
  185. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -1,20 +1,7 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
- class Transaction #:nodoc:
4
- attr_reader :connection
5
-
6
- def initialize(connection)
7
- @connection = connection
8
- @state = TransactionState.new
9
- end
10
-
11
- def state
12
- @state
13
- end
14
- end
15
-
16
3
  class TransactionState
17
- attr_accessor :parent
4
+ attr_reader :parent
18
5
 
19
6
  VALID_STATES = Set.new([:committed, :rolledback, nil])
20
7
 
@@ -35,6 +22,10 @@ module ActiveRecord
35
22
  @state == :rolledback
36
23
  end
37
24
 
25
+ def completed?
26
+ committed? || rolledback?
27
+ end
28
+
38
29
  def set_state(state)
39
30
  if !VALID_STATES.include?(state)
40
31
  raise ArgumentError, "Invalid transaction state: #{state}"
@@ -43,127 +34,106 @@ module ActiveRecord
43
34
  end
44
35
  end
45
36
 
46
- class ClosedTransaction < Transaction #:nodoc:
47
- def number
48
- 0
49
- end
50
-
51
- def begin(options = {})
52
- RealTransaction.new(connection, self, options)
53
- end
54
-
55
- def closed?
56
- true
57
- end
58
-
59
- def open?
60
- false
61
- end
62
-
63
- def joinable?
64
- false
65
- end
66
-
67
- # This is a noop when there are no open transactions
68
- def add_record(record)
69
- end
37
+ class NullTransaction #:nodoc:
38
+ def initialize; end
39
+ def closed?; true; end
40
+ def open?; false; end
41
+ def joinable?; false; end
42
+ def add_record(record); end
70
43
  end
71
44
 
72
- class OpenTransaction < Transaction #:nodoc:
73
- attr_reader :parent, :records
74
- attr_writer :joinable
75
-
76
- def initialize(connection, parent, options = {})
77
- super connection
78
-
79
- @parent = parent
80
- @records = []
81
- @finishing = false
82
- @joinable = options.fetch(:joinable, true)
83
- end
84
-
85
- # This state is necessary so that we correctly handle stuff that might
86
- # happen in a commit/rollback. But it's kinda distasteful. Maybe we can
87
- # find a better way to structure it in the future.
88
- def finishing?
89
- @finishing
90
- end
45
+ class Transaction #:nodoc:
91
46
 
92
- def joinable?
93
- @joinable && !finishing?
94
- end
47
+ attr_reader :connection, :state, :records, :savepoint_name
48
+ attr_writer :joinable
95
49
 
96
- def number
97
- if finishing?
98
- parent.number
99
- else
100
- parent.number + 1
101
- end
50
+ def initialize(connection, options)
51
+ @connection = connection
52
+ @state = TransactionState.new
53
+ @records = []
54
+ @joinable = options.fetch(:joinable, true)
102
55
  end
103
56
 
104
- def begin(options = {})
105
- if finishing?
106
- parent.begin
107
- else
108
- SavepointTransaction.new(connection, self, options)
109
- end
57
+ def add_record(record)
58
+ records << record
110
59
  end
111
60
 
112
61
  def rollback
113
- @finishing = true
114
- perform_rollback
115
- parent
116
- end
117
-
118
- def commit
119
- @finishing = true
120
- perform_commit
121
- parent
122
- end
123
-
124
- def add_record(record)
125
- if record.has_transactional_callbacks?
126
- records << record
127
- else
128
- record.set_transaction_state(@state)
129
- end
62
+ @state.set_state(:rolledback)
130
63
  end
131
64
 
132
65
  def rollback_records
133
- @state.set_state(:rolledback)
134
- records.uniq.each do |record|
66
+ ite = records.uniq
67
+ while record = ite.shift
135
68
  begin
136
- record.rolledback!(parent.closed?)
69
+ record.rolledback! full_rollback?
137
70
  rescue => e
71
+ raise if ActiveRecord::Base.raise_in_transactional_callbacks
138
72
  record.logger.error(e) if record.respond_to?(:logger) && record.logger
139
73
  end
140
74
  end
75
+ ensure
76
+ ite.each do |i|
77
+ i.rolledback!(full_rollback?, false)
78
+ end
141
79
  end
142
80
 
143
- def commit_records
81
+ def commit
144
82
  @state.set_state(:committed)
145
- records.uniq.each do |record|
83
+ end
84
+
85
+ def commit_records
86
+ ite = records.uniq
87
+ while record = ite.shift
146
88
  begin
147
89
  record.committed!
148
90
  rescue => e
91
+ raise if ActiveRecord::Base.raise_in_transactional_callbacks
149
92
  record.logger.error(e) if record.respond_to?(:logger) && record.logger
150
93
  end
151
94
  end
95
+ ensure
96
+ ite.each do |i|
97
+ i.committed!(false)
98
+ end
152
99
  end
153
100
 
154
- def closed?
155
- false
101
+ def full_rollback?; true; end
102
+ def joinable?; @joinable; end
103
+ def closed?; false; end
104
+ def open?; !closed?; end
105
+ end
106
+
107
+ class SavepointTransaction < Transaction
108
+
109
+ def initialize(connection, savepoint_name, options)
110
+ super(connection, options)
111
+ if options[:isolation]
112
+ raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
113
+ end
114
+ connection.create_savepoint(@savepoint_name = savepoint_name)
156
115
  end
157
116
 
158
- def open?
159
- true
117
+ def rollback
118
+ connection.rollback_to_savepoint(savepoint_name)
119
+ super
120
+ rollback_records
160
121
  end
161
- end
162
122
 
163
- class RealTransaction < OpenTransaction #:nodoc:
164
- def initialize(connection, parent, options = {})
123
+ def commit
124
+ connection.release_savepoint(savepoint_name)
165
125
  super
126
+ parent = connection.transaction_manager.current_transaction
127
+ records.each { |r| parent.add_record(r) }
128
+ end
129
+
130
+ def full_rollback?; false; end
131
+ end
166
132
 
133
+ class RealTransaction < Transaction
134
+
135
+ def initialize(connection, options)
136
+ super
167
137
  if options[:isolation]
168
138
  connection.begin_isolated_db_transaction(options[:isolation])
169
139
  else
@@ -171,38 +141,75 @@ module ActiveRecord
171
141
  end
172
142
  end
173
143
 
174
- def perform_rollback
144
+ def rollback
175
145
  connection.rollback_db_transaction
146
+ super
176
147
  rollback_records
177
148
  end
178
149
 
179
- def perform_commit
150
+ def commit
180
151
  connection.commit_db_transaction
152
+ super
181
153
  commit_records
182
154
  end
183
155
  end
184
156
 
185
- class SavepointTransaction < OpenTransaction #:nodoc:
186
- def initialize(connection, parent, options = {})
187
- if options[:isolation]
188
- raise ActiveRecord::TransactionIsolationError, "cannot set transaction isolation in a nested transaction"
189
- end
157
+ class TransactionManager #:nodoc:
158
+ def initialize(connection)
159
+ @stack = []
160
+ @connection = connection
161
+ end
190
162
 
191
- super
192
- connection.create_savepoint
163
+ def begin_transaction(options = {})
164
+ transaction =
165
+ if @stack.empty?
166
+ RealTransaction.new(@connection, options)
167
+ else
168
+ SavepointTransaction.new(@connection, "active_record_#{@stack.size}", options)
169
+ end
170
+ @stack.push(transaction)
171
+ transaction
172
+ end
173
+
174
+ def commit_transaction
175
+ @stack.pop.commit
176
+ end
177
+
178
+ def rollback_transaction
179
+ @stack.pop.rollback
180
+ end
181
+
182
+ def within_new_transaction(options = {})
183
+ transaction = begin_transaction options
184
+ yield
185
+ rescue Exception => error
186
+ rollback_transaction if transaction
187
+ raise
188
+ ensure
189
+ unless error
190
+ if Thread.current.status == 'aborting'
191
+ rollback_transaction if transaction
192
+ else
193
+ begin
194
+ commit_transaction
195
+ rescue Exception
196
+ transaction.rollback unless transaction.state.completed?
197
+ raise
198
+ end
199
+ end
200
+ end
193
201
  end
194
202
 
195
- def perform_rollback
196
- connection.rollback_to_savepoint
197
- rollback_records
203
+ def open_transactions
204
+ @stack.size
198
205
  end
199
206
 
200
- def perform_commit
201
- @state.set_state(:committed)
202
- @state.parent = parent.state
203
- connection.release_savepoint
204
- records.each { |r| parent.add_record(r) }
207
+ def current_transaction
208
+ @stack.last || NULL_TRANSACTION
205
209
  end
210
+
211
+ private
212
+ NULL_TRANSACTION = NullTransaction.new
206
213
  end
207
214
  end
208
215
  end
@@ -1,11 +1,14 @@
1
1
  require 'date'
2
2
  require 'bigdecimal'
3
3
  require 'bigdecimal/util'
4
+ require 'active_record/type'
4
5
  require 'active_support/core_ext/benchmark'
5
6
  require 'active_record/connection_adapters/schema_cache'
6
7
  require 'active_record/connection_adapters/abstract/schema_dumper'
7
8
  require 'active_record/connection_adapters/abstract/schema_creation'
8
9
  require 'monitor'
10
+ require 'arel/collectors/bind'
11
+ require 'arel/collectors/sql_string'
9
12
 
10
13
  module ActiveRecord
11
14
  module ConnectionAdapters # :nodoc:
@@ -21,6 +24,7 @@ module ActiveRecord
21
24
  autoload :TableDefinition
22
25
  autoload :Table
23
26
  autoload :AlterTable
27
+ autoload :TimestampDefaultDeprecation
24
28
  end
25
29
 
26
30
  autoload_at 'active_record/connection_adapters/abstract/connection_pool' do
@@ -39,7 +43,8 @@ module ActiveRecord
39
43
  end
40
44
 
41
45
  autoload_at 'active_record/connection_adapters/abstract/transaction' do
42
- autoload :ClosedTransaction
46
+ autoload :TransactionManager
47
+ autoload :NullTransaction
43
48
  autoload :RealTransaction
44
49
  autoload :SavepointTransaction
45
50
  autoload :TransactionState
@@ -59,6 +64,7 @@ module ActiveRecord
59
64
  # Most of the methods in the adapter are useful during migrations. Most
60
65
  # notably, the instance methods provided by SchemaStatement are very useful.
61
66
  class AbstractAdapter
67
+ ADAPTER_NAME = 'Abstract'.freeze
62
68
  include Quoting, DatabaseStatements, SchemaStatements
63
69
  include DatabaseLimits
64
70
  include QueryCache
@@ -71,8 +77,8 @@ module ActiveRecord
71
77
  define_callbacks :checkout, :checkin
72
78
 
73
79
  attr_accessor :visitor, :pool
74
- attr_reader :schema_cache, :last_use, :in_use, :logger
75
- alias :in_use? :in_use
80
+ attr_reader :schema_cache, :owner, :logger
81
+ alias :in_use? :owner
76
82
 
77
83
  def self.type_cast_config_to_integer(config)
78
84
  if config =~ SIMPLE_INT
@@ -90,13 +96,14 @@ module ActiveRecord
90
96
  end
91
97
  end
92
98
 
99
+ attr_reader :prepared_statements
100
+
93
101
  def initialize(connection, logger = nil, pool = nil) #:nodoc:
94
102
  super()
95
103
 
96
104
  @connection = connection
97
- @in_use = false
105
+ @owner = nil
98
106
  @instrumenter = ActiveSupport::Notifications.instrumenter
99
- @last_use = false
100
107
  @logger = logger
101
108
  @pool = pool
102
109
  @schema_cache = SchemaCache.new self
@@ -104,6 +111,38 @@ module ActiveRecord
104
111
  @prepared_statements = false
105
112
  end
106
113
 
114
+ class Version
115
+ include Comparable
116
+
117
+ def initialize(version_string)
118
+ @version = version_string.split('.').map(&:to_i)
119
+ end
120
+
121
+ def <=>(version_string)
122
+ @version <=> version_string.split('.').map(&:to_i)
123
+ end
124
+ end
125
+
126
+ class BindCollector < Arel::Collectors::Bind
127
+ def compile(bvs, conn)
128
+ super(bvs.map { |bv| conn.quote(*bv.reverse) })
129
+ end
130
+ end
131
+
132
+ class SQLString < Arel::Collectors::SQLString
133
+ def compile(bvs, conn)
134
+ super(bvs)
135
+ end
136
+ end
137
+
138
+ def collector
139
+ if prepared_statements
140
+ SQLString.new
141
+ else
142
+ BindCollector.new
143
+ end
144
+ end
145
+
107
146
  def valid_type?(type)
108
147
  true
109
148
  end
@@ -114,9 +153,8 @@ module ActiveRecord
114
153
 
115
154
  def lease
116
155
  synchronize do
117
- unless in_use
118
- @in_use = true
119
- @last_use = Time.now
156
+ unless in_use?
157
+ @owner = Thread.current
120
158
  end
121
159
  end
122
160
  end
@@ -127,49 +165,35 @@ module ActiveRecord
127
165
  end
128
166
 
129
167
  def expire
130
- @in_use = false
131
- end
132
-
133
- def unprepared_visitor
134
- self.class::BindSubstitution.new self
168
+ @owner = nil
135
169
  end
136
170
 
137
171
  def unprepared_statement
138
172
  old_prepared_statements, @prepared_statements = @prepared_statements, false
139
- old_visitor, @visitor = @visitor, unprepared_visitor
140
173
  yield
141
174
  ensure
142
- @visitor, @prepared_statements = old_visitor, old_prepared_statements
175
+ @prepared_statements = old_prepared_statements
143
176
  end
144
177
 
145
178
  # Returns the human-readable name of the adapter. Use mixed case - one
146
179
  # can always use downcase if needed.
147
180
  def adapter_name
148
- 'Abstract'
181
+ self.class::ADAPTER_NAME
149
182
  end
150
183
 
151
- # Does this adapter support migrations? Backend specific, as the
152
- # abstract adapter always returns +false+.
184
+ # Does this adapter support migrations?
153
185
  def supports_migrations?
154
186
  false
155
187
  end
156
188
 
157
189
  # Can this adapter determine the primary key for tables not attached
158
- # to an Active Record class, such as join tables? Backend specific, as
159
- # the abstract adapter always returns +false+.
190
+ # to an Active Record class, such as join tables?
160
191
  def supports_primary_key?
161
192
  false
162
193
  end
163
194
 
164
- # Does this adapter support using DISTINCT within COUNT? This is +true+
165
- # for all adapters except sqlite.
166
- def supports_count_distinct?
167
- true
168
- end
169
-
170
195
  # Does this adapter support DDL rollbacks in transactions? That is, would
171
- # CREATE TABLE or ALTER TABLE get rolled back by a transaction? PostgreSQL,
172
- # SQL Server, and others support this. MySQL and others do not.
196
+ # CREATE TABLE or ALTER TABLE get rolled back by a transaction?
173
197
  def supports_ddl_transactions?
174
198
  false
175
199
  end
@@ -178,8 +202,7 @@ module ActiveRecord
178
202
  false
179
203
  end
180
204
 
181
- # Does this adapter support savepoints? PostgreSQL and MySQL do,
182
- # SQLite < 3.6.8 does not.
205
+ # Does this adapter support savepoints?
183
206
  def supports_savepoints?
184
207
  false
185
208
  end
@@ -187,7 +210,6 @@ module ActiveRecord
187
210
  # Should primary key values be selected from their corresponding
188
211
  # sequence before the insert statement? If true, next_sequence_value
189
212
  # is called before each insert to set the record's primary key.
190
- # This is false for all adapters but Firebird.
191
213
  def prefetch_primary_key?(table_name = nil)
192
214
  false
193
215
  end
@@ -202,8 +224,7 @@ module ActiveRecord
202
224
  false
203
225
  end
204
226
 
205
- # Does this adapter support explain? As of this writing sqlite3,
206
- # mysql2, and postgresql are the only ones that do.
227
+ # Does this adapter support explain?
207
228
  def supports_explain?
208
229
  false
209
230
  end
@@ -213,12 +234,27 @@ module ActiveRecord
213
234
  false
214
235
  end
215
236
 
216
- # Does this adapter support database extensions? As of this writing only
217
- # postgresql does.
237
+ # Does this adapter support database extensions?
218
238
  def supports_extensions?
219
239
  false
220
240
  end
221
241
 
242
+ # Does this adapter support creating indexes in the same statement as
243
+ # creating the table?
244
+ def supports_indexes_in_create?
245
+ false
246
+ end
247
+
248
+ # Does this adapter support creating foreign key constraints?
249
+ def supports_foreign_keys?
250
+ false
251
+ end
252
+
253
+ # Does this adapter support views?
254
+ def supports_views?
255
+ false
256
+ end
257
+
222
258
  # This is meant to be implemented by the adapters that support extensions
223
259
  def disable_extension(name)
224
260
  end
@@ -227,24 +263,22 @@ module ActiveRecord
227
263
  def enable_extension(name)
228
264
  end
229
265
 
230
- # A list of extensions, to be filled in by adapters that support them. At
231
- # the moment only postgresql does.
266
+ # A list of extensions, to be filled in by adapters that support them.
232
267
  def extensions
233
268
  []
234
269
  end
235
270
 
236
271
  # A list of index algorithms, to be filled by adapters that support them.
237
- # MySQL and PostgreSQL have support for them right now.
238
272
  def index_algorithms
239
273
  {}
240
274
  end
241
275
 
242
276
  # QUOTING ==================================================
243
277
 
244
- # Returns a bind substitution value given a bind +index+ and +column+
278
+ # Returns a bind substitution value given a bind +column+
245
279
  # NOTE: The column param is currently being used by the sqlserver-adapter
246
- def substitute_at(column, index)
247
- Arel::Nodes::BindParam.new '?'
280
+ def substitute_at(column, _unused = 0)
281
+ Arel::Nodes::BindParam.new
248
282
  end
249
283
 
250
284
  # REFERENTIAL INTEGRITY ====================================
@@ -262,12 +296,6 @@ module ActiveRecord
262
296
  def active?
263
297
  end
264
298
 
265
- # Adapter should redefine this if it needs a threadsafe way to approximate
266
- # if the connection is active
267
- def active_threadsafe?
268
- active?
269
- end
270
-
271
299
  # Disconnects from the database if already connected, and establishes a
272
300
  # new connection with the database. Implementors should call super if they
273
301
  # override the default implementation.
@@ -301,7 +329,6 @@ module ActiveRecord
301
329
  end
302
330
 
303
331
  # Returns true if its required to reload the connection between requests for development mode.
304
- # This is not the case for Ruby/MySQL and it's not necessary for any adapters except SQLite.
305
332
  def requires_reloading?
306
333
  false
307
334
  end
@@ -323,29 +350,28 @@ module ActiveRecord
323
350
  @connection
324
351
  end
325
352
 
326
- def open_transactions
327
- @transaction.number
328
- end
329
-
330
353
  def create_savepoint(name = nil)
331
354
  end
332
355
 
333
- def rollback_to_savepoint(name = nil)
334
- end
335
-
336
356
  def release_savepoint(name = nil)
337
357
  end
338
358
 
339
- def case_sensitive_modifier(node)
359
+ def case_sensitive_modifier(node, table_attribute)
340
360
  node
341
361
  end
342
362
 
363
+ def case_sensitive_comparison(table, attribute, column, value)
364
+ table_attr = table[attribute]
365
+ value = case_sensitive_modifier(value, table_attr) unless value.nil?
366
+ table_attr.eq(value)
367
+ end
368
+
343
369
  def case_insensitive_comparison(table, attribute, column, value)
344
370
  table[attribute].lower.eq(table.lower(value))
345
371
  end
346
372
 
347
373
  def current_savepoint_name
348
- "active_record_#{open_transactions}"
374
+ current_transaction.savepoint_name
349
375
  end
350
376
 
351
377
  # Check the connection back in to the connection pool
@@ -353,8 +379,89 @@ module ActiveRecord
353
379
  pool.checkin self
354
380
  end
355
381
 
382
+ def type_map # :nodoc:
383
+ @type_map ||= Type::TypeMap.new.tap do |mapping|
384
+ initialize_type_map(mapping)
385
+ end
386
+ end
387
+
388
+ def new_column(name, default, cast_type, sql_type = nil, null = true)
389
+ Column.new(name, default, cast_type, sql_type, null)
390
+ end
391
+
392
+ def lookup_cast_type(sql_type) # :nodoc:
393
+ type_map.lookup(sql_type)
394
+ end
395
+
396
+ def column_name_for_operation(operation, node) # :nodoc:
397
+ visitor.accept(node, collector).value
398
+ end
399
+
356
400
  protected
357
401
 
402
+ def initialize_type_map(m) # :nodoc:
403
+ register_class_with_limit m, %r(boolean)i, Type::Boolean
404
+ register_class_with_limit m, %r(char)i, Type::String
405
+ register_class_with_limit m, %r(binary)i, Type::Binary
406
+ register_class_with_limit m, %r(text)i, Type::Text
407
+ register_class_with_limit m, %r(date)i, Type::Date
408
+ register_class_with_limit m, %r(time)i, Type::Time
409
+ register_class_with_limit m, %r(datetime)i, Type::DateTime
410
+ register_class_with_limit m, %r(float)i, Type::Float
411
+ register_class_with_limit m, %r(int)i, Type::Integer
412
+
413
+ m.alias_type %r(blob)i, 'binary'
414
+ m.alias_type %r(clob)i, 'text'
415
+ m.alias_type %r(timestamp)i, 'datetime'
416
+ m.alias_type %r(numeric)i, 'decimal'
417
+ m.alias_type %r(number)i, 'decimal'
418
+ m.alias_type %r(double)i, 'float'
419
+
420
+ m.register_type(%r(decimal)i) do |sql_type|
421
+ scale = extract_scale(sql_type)
422
+ precision = extract_precision(sql_type)
423
+
424
+ if scale == 0
425
+ # FIXME: Remove this class as well
426
+ Type::DecimalWithoutScale.new(precision: precision)
427
+ else
428
+ Type::Decimal.new(precision: precision, scale: scale)
429
+ end
430
+ end
431
+ end
432
+
433
+ def reload_type_map # :nodoc:
434
+ type_map.clear
435
+ initialize_type_map(type_map)
436
+ end
437
+
438
+ def register_class_with_limit(mapping, key, klass) # :nodoc:
439
+ mapping.register_type(key) do |*args|
440
+ limit = extract_limit(args.last)
441
+ klass.new(limit: limit)
442
+ end
443
+ end
444
+
445
+ def extract_scale(sql_type) # :nodoc:
446
+ case sql_type
447
+ when /\((\d+)\)/ then 0
448
+ when /\((\d+)(,(\d+))\)/ then $3.to_i
449
+ end
450
+ end
451
+
452
+ def extract_precision(sql_type) # :nodoc:
453
+ $1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
454
+ end
455
+
456
+ def extract_limit(sql_type) # :nodoc:
457
+ case sql_type
458
+ when /^bigint/i
459
+ 8
460
+ when /\((.*)\)/
461
+ $1.to_i
462
+ end
463
+ end
464
+
358
465
  def translate_exception_class(e, sql)
359
466
  begin
360
467
  message = "#{e.class.name}: #{e.message}: #{sql}"
@@ -362,7 +469,6 @@ module ActiveRecord
362
469
  message = "#{e.class.name}: #{e.message.force_encoding sql.encoding}: #{sql}"
363
470
  end
364
471
 
365
- @logger.error message if @logger
366
472
  exception = translate_exception(e, message)
367
473
  exception.set_backtrace e.backtrace
368
474
  exception
@@ -386,7 +492,13 @@ module ActiveRecord
386
492
  end
387
493
 
388
494
  def without_prepared_statement?(binds)
389
- !@prepared_statements || binds.empty?
495
+ !prepared_statements || binds.empty?
496
+ end
497
+
498
+ def column_for(table_name, column_name) # :nodoc:
499
+ column_name = column_name.to_s
500
+ columns(table_name).detect { |c| c.name == column_name } ||
501
+ raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}")
390
502
  end
391
503
  end
392
504
  end