activerecord 4.1.16 → 4.2.0.beta1

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