activerecord 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/CHANGELOG.md +1372 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +218 -0
- data/examples/performance.rb +184 -0
- data/examples/simple.rb +14 -0
- data/lib/active_record.rb +173 -0
- data/lib/active_record/aggregations.rb +266 -0
- data/lib/active_record/association_relation.rb +22 -0
- data/lib/active_record/associations.rb +1724 -0
- data/lib/active_record/associations/alias_tracker.rb +87 -0
- data/lib/active_record/associations/association.rb +253 -0
- data/lib/active_record/associations/association_scope.rb +194 -0
- data/lib/active_record/associations/belongs_to_association.rb +111 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +40 -0
- data/lib/active_record/associations/builder/association.rb +149 -0
- data/lib/active_record/associations/builder/belongs_to.rb +116 -0
- data/lib/active_record/associations/builder/collection_association.rb +91 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +124 -0
- data/lib/active_record/associations/builder/has_many.rb +15 -0
- data/lib/active_record/associations/builder/has_one.rb +23 -0
- data/lib/active_record/associations/builder/singular_association.rb +38 -0
- data/lib/active_record/associations/collection_association.rb +634 -0
- data/lib/active_record/associations/collection_proxy.rb +1027 -0
- data/lib/active_record/associations/has_many_association.rb +184 -0
- data/lib/active_record/associations/has_many_through_association.rb +238 -0
- data/lib/active_record/associations/has_one_association.rb +105 -0
- data/lib/active_record/associations/has_one_through_association.rb +36 -0
- data/lib/active_record/associations/join_dependency.rb +282 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +122 -0
- data/lib/active_record/associations/join_dependency/join_base.rb +22 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
- data/lib/active_record/associations/preloader.rb +203 -0
- data/lib/active_record/associations/preloader/association.rb +162 -0
- data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
- data/lib/active_record/associations/preloader/collection_association.rb +24 -0
- data/lib/active_record/associations/preloader/has_many.rb +17 -0
- data/lib/active_record/associations/preloader/has_many_through.rb +19 -0
- data/lib/active_record/associations/preloader/has_one.rb +23 -0
- data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
- data/lib/active_record/associations/preloader/singular_association.rb +21 -0
- data/lib/active_record/associations/preloader/through_association.rb +96 -0
- data/lib/active_record/associations/singular_association.rb +86 -0
- data/lib/active_record/associations/through_association.rb +96 -0
- data/lib/active_record/attribute.rb +149 -0
- data/lib/active_record/attribute_assignment.rb +212 -0
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods.rb +439 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +71 -0
- data/lib/active_record/attribute_methods/dirty.rb +181 -0
- data/lib/active_record/attribute_methods/primary_key.rb +128 -0
- data/lib/active_record/attribute_methods/query.rb +40 -0
- data/lib/active_record/attribute_methods/read.rb +103 -0
- data/lib/active_record/attribute_methods/serialization.rb +70 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -0
- data/lib/active_record/attribute_methods/write.rb +83 -0
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attribute_set/builder.rb +86 -0
- data/lib/active_record/attributes.rb +139 -0
- data/lib/active_record/autosave_association.rb +439 -0
- data/lib/active_record/base.rb +317 -0
- data/lib/active_record/callbacks.rb +313 -0
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/coders/yaml_column.rb +38 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +659 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +67 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +373 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +133 -0
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +574 -0
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +991 -0
- data/lib/active_record/connection_adapters/abstract/transaction.rb +219 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +487 -0
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +883 -0
- data/lib/active_record/connection_adapters/column.rb +82 -0
- data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +282 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +491 -0
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +99 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +588 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +754 -0
- data/lib/active_record/connection_adapters/schema_cache.rb +94 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +628 -0
- data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
- data/lib/active_record/connection_handling.rb +132 -0
- data/lib/active_record/core.rb +566 -0
- data/lib/active_record/counter_cache.rb +175 -0
- data/lib/active_record/dynamic_matchers.rb +140 -0
- data/lib/active_record/enum.rb +198 -0
- data/lib/active_record/errors.rb +252 -0
- data/lib/active_record/explain.rb +38 -0
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +29 -0
- data/lib/active_record/fixture_set/file.rb +56 -0
- data/lib/active_record/fixtures.rb +1007 -0
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +247 -0
- data/lib/active_record/integration.rb +113 -0
- data/lib/active_record/locale/en.yml +47 -0
- data/lib/active_record/locking/optimistic.rb +204 -0
- data/lib/active_record/locking/pessimistic.rb +77 -0
- data/lib/active_record/log_subscriber.rb +75 -0
- data/lib/active_record/migration.rb +1051 -0
- data/lib/active_record/migration/command_recorder.rb +197 -0
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/model_schema.rb +340 -0
- data/lib/active_record/nested_attributes.rb +548 -0
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +81 -0
- data/lib/active_record/persistence.rb +532 -0
- data/lib/active_record/query_cache.rb +56 -0
- data/lib/active_record/querying.rb +68 -0
- data/lib/active_record/railtie.rb +162 -0
- data/lib/active_record/railties/console_sandbox.rb +5 -0
- data/lib/active_record/railties/controller_runtime.rb +50 -0
- data/lib/active_record/railties/databases.rake +391 -0
- data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
- data/lib/active_record/readonly_attributes.rb +23 -0
- data/lib/active_record/reflection.rb +881 -0
- data/lib/active_record/relation.rb +681 -0
- data/lib/active_record/relation/batches.rb +138 -0
- data/lib/active_record/relation/calculations.rb +403 -0
- data/lib/active_record/relation/delegation.rb +140 -0
- data/lib/active_record/relation/finder_methods.rb +528 -0
- data/lib/active_record/relation/merger.rb +170 -0
- data/lib/active_record/relation/predicate_builder.rb +126 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +47 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
- data/lib/active_record/relation/query_methods.rb +1176 -0
- data/lib/active_record/relation/spawn_methods.rb +75 -0
- data/lib/active_record/result.rb +131 -0
- data/lib/active_record/runtime_registry.rb +22 -0
- data/lib/active_record/sanitization.rb +191 -0
- data/lib/active_record/schema.rb +64 -0
- data/lib/active_record/schema_dumper.rb +251 -0
- data/lib/active_record/schema_migration.rb +56 -0
- data/lib/active_record/scoping.rb +87 -0
- data/lib/active_record/scoping/default.rb +134 -0
- data/lib/active_record/scoping/named.rb +164 -0
- data/lib/active_record/serialization.rb +22 -0
- data/lib/active_record/serializers/xml_serializer.rb +193 -0
- data/lib/active_record/statement_cache.rb +111 -0
- data/lib/active_record/store.rb +205 -0
- data/lib/active_record/tasks/database_tasks.rb +296 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +145 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
- data/lib/active_record/timestamp.rb +121 -0
- data/lib/active_record/transactions.rb +417 -0
- data/lib/active_record/translation.rb +22 -0
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +30 -0
- data/lib/active_record/type/date.rb +46 -0
- data/lib/active_record/type/date_time.rb +43 -0
- data/lib/active_record/type/decimal.rb +40 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +17 -0
- data/lib/active_record/type/integer.rb +55 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +56 -0
- data/lib/active_record/type/string.rb +36 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +101 -0
- data/lib/active_record/validations.rb +90 -0
- data/lib/active_record/validations/associated.rb +51 -0
- data/lib/active_record/validations/presence.rb +67 -0
- data/lib/active_record/validations/uniqueness.rb +229 -0
- data/lib/active_record/version.rb +8 -0
- data/lib/rails/generators/active_record.rb +17 -0
- data/lib/rails/generators/active_record/migration.rb +18 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +70 -0
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +22 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +45 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +52 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +10 -0
- data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
- metadata +309 -0
@@ -0,0 +1,219 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
class TransactionState
|
4
|
+
attr_reader :parent
|
5
|
+
|
6
|
+
VALID_STATES = Set.new([:committed, :rolledback, nil])
|
7
|
+
|
8
|
+
def initialize(state = nil)
|
9
|
+
@state = state
|
10
|
+
@parent = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def finalized?
|
14
|
+
@state
|
15
|
+
end
|
16
|
+
|
17
|
+
def committed?
|
18
|
+
@state == :committed
|
19
|
+
end
|
20
|
+
|
21
|
+
def rolledback?
|
22
|
+
@state == :rolledback
|
23
|
+
end
|
24
|
+
|
25
|
+
def completed?
|
26
|
+
committed? || rolledback?
|
27
|
+
end
|
28
|
+
|
29
|
+
def set_state(state)
|
30
|
+
if !VALID_STATES.include?(state)
|
31
|
+
raise ArgumentError, "Invalid transaction state: #{state}"
|
32
|
+
end
|
33
|
+
@state = state
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
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
|
43
|
+
end
|
44
|
+
|
45
|
+
class Transaction #:nodoc:
|
46
|
+
|
47
|
+
attr_reader :connection, :state, :records, :savepoint_name
|
48
|
+
attr_writer :joinable
|
49
|
+
|
50
|
+
def initialize(connection, options)
|
51
|
+
@connection = connection
|
52
|
+
@state = TransactionState.new
|
53
|
+
@records = []
|
54
|
+
@joinable = options.fetch(:joinable, true)
|
55
|
+
end
|
56
|
+
|
57
|
+
def add_record(record)
|
58
|
+
if record.has_transactional_callbacks?
|
59
|
+
records << record
|
60
|
+
else
|
61
|
+
record.set_transaction_state(@state)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def rollback
|
66
|
+
@state.set_state(:rolledback)
|
67
|
+
end
|
68
|
+
|
69
|
+
def rollback_records
|
70
|
+
ite = records.uniq
|
71
|
+
while record = ite.shift
|
72
|
+
begin
|
73
|
+
record.rolledback! full_rollback?
|
74
|
+
rescue => e
|
75
|
+
raise if ActiveRecord::Base.raise_in_transactional_callbacks
|
76
|
+
record.logger.error(e) if record.respond_to?(:logger) && record.logger
|
77
|
+
end
|
78
|
+
end
|
79
|
+
ensure
|
80
|
+
ite.each do |i|
|
81
|
+
i.rolledback!(full_rollback?, false)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def commit
|
86
|
+
@state.set_state(:committed)
|
87
|
+
end
|
88
|
+
|
89
|
+
def commit_records
|
90
|
+
ite = records.uniq
|
91
|
+
while record = ite.shift
|
92
|
+
begin
|
93
|
+
record.committed!
|
94
|
+
rescue => e
|
95
|
+
raise if ActiveRecord::Base.raise_in_transactional_callbacks
|
96
|
+
record.logger.error(e) if record.respond_to?(:logger) && record.logger
|
97
|
+
end
|
98
|
+
end
|
99
|
+
ensure
|
100
|
+
ite.each do |i|
|
101
|
+
i.committed!(false)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
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)
|
119
|
+
end
|
120
|
+
|
121
|
+
def rollback
|
122
|
+
connection.rollback_to_savepoint(savepoint_name)
|
123
|
+
super
|
124
|
+
rollback_records
|
125
|
+
end
|
126
|
+
|
127
|
+
def commit
|
128
|
+
connection.release_savepoint(savepoint_name)
|
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
|
136
|
+
|
137
|
+
class RealTransaction < Transaction
|
138
|
+
|
139
|
+
def initialize(connection, options)
|
140
|
+
super
|
141
|
+
if options[:isolation]
|
142
|
+
connection.begin_isolated_db_transaction(options[:isolation])
|
143
|
+
else
|
144
|
+
connection.begin_db_transaction
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def rollback
|
149
|
+
connection.rollback_db_transaction
|
150
|
+
super
|
151
|
+
rollback_records
|
152
|
+
end
|
153
|
+
|
154
|
+
def commit
|
155
|
+
connection.commit_db_transaction
|
156
|
+
super
|
157
|
+
commit_records
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class TransactionManager #:nodoc:
|
162
|
+
def initialize(connection)
|
163
|
+
@stack = []
|
164
|
+
@connection = connection
|
165
|
+
end
|
166
|
+
|
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
|
176
|
+
end
|
177
|
+
|
178
|
+
def commit_transaction
|
179
|
+
@stack.pop.commit
|
180
|
+
end
|
181
|
+
|
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
|
+
unless error
|
194
|
+
if Thread.current.status == 'aborting'
|
195
|
+
rollback_transaction
|
196
|
+
else
|
197
|
+
begin
|
198
|
+
commit_transaction
|
199
|
+
rescue Exception
|
200
|
+
transaction.rollback unless transaction.state.completed?
|
201
|
+
raise
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def open_transactions
|
208
|
+
@stack.size
|
209
|
+
end
|
210
|
+
|
211
|
+
def current_transaction
|
212
|
+
@stack.last || NULL_TRANSACTION
|
213
|
+
end
|
214
|
+
|
215
|
+
private
|
216
|
+
NULL_TRANSACTION = NullTransaction.new
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
@@ -0,0 +1,487 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'bigdecimal'
|
3
|
+
require 'bigdecimal/util'
|
4
|
+
require 'active_record/type'
|
5
|
+
require 'active_support/core_ext/benchmark'
|
6
|
+
require 'active_record/connection_adapters/schema_cache'
|
7
|
+
require 'active_record/connection_adapters/abstract/schema_dumper'
|
8
|
+
require 'active_record/connection_adapters/abstract/schema_creation'
|
9
|
+
require 'monitor'
|
10
|
+
require 'arel/collectors/bind'
|
11
|
+
require 'arel/collectors/sql_string'
|
12
|
+
|
13
|
+
module ActiveRecord
|
14
|
+
module ConnectionAdapters # :nodoc:
|
15
|
+
extend ActiveSupport::Autoload
|
16
|
+
|
17
|
+
autoload :Column
|
18
|
+
autoload :ConnectionSpecification
|
19
|
+
|
20
|
+
autoload_at 'active_record/connection_adapters/abstract/schema_definitions' do
|
21
|
+
autoload :IndexDefinition
|
22
|
+
autoload :ColumnDefinition
|
23
|
+
autoload :ChangeColumnDefinition
|
24
|
+
autoload :TableDefinition
|
25
|
+
autoload :Table
|
26
|
+
autoload :AlterTable
|
27
|
+
autoload :TimestampDefaultDeprecation
|
28
|
+
end
|
29
|
+
|
30
|
+
autoload_at 'active_record/connection_adapters/abstract/connection_pool' do
|
31
|
+
autoload :ConnectionHandler
|
32
|
+
autoload :ConnectionManagement
|
33
|
+
end
|
34
|
+
|
35
|
+
autoload_under 'abstract' do
|
36
|
+
autoload :SchemaStatements
|
37
|
+
autoload :DatabaseStatements
|
38
|
+
autoload :DatabaseLimits
|
39
|
+
autoload :Quoting
|
40
|
+
autoload :ConnectionPool
|
41
|
+
autoload :QueryCache
|
42
|
+
autoload :Savepoints
|
43
|
+
end
|
44
|
+
|
45
|
+
autoload_at 'active_record/connection_adapters/abstract/transaction' do
|
46
|
+
autoload :TransactionManager
|
47
|
+
autoload :NullTransaction
|
48
|
+
autoload :RealTransaction
|
49
|
+
autoload :SavepointTransaction
|
50
|
+
autoload :TransactionState
|
51
|
+
end
|
52
|
+
|
53
|
+
# Active Record supports multiple database systems. AbstractAdapter and
|
54
|
+
# related classes form the abstraction layer which makes this possible.
|
55
|
+
# An AbstractAdapter represents a connection to a database, and provides an
|
56
|
+
# abstract interface for database-specific functionality such as establishing
|
57
|
+
# a connection, escaping values, building the right SQL fragments for ':offset'
|
58
|
+
# and ':limit' options, etc.
|
59
|
+
#
|
60
|
+
# All the concrete database adapters follow the interface laid down in this class.
|
61
|
+
# ActiveRecord::Base.connection returns an AbstractAdapter object, which
|
62
|
+
# you can use.
|
63
|
+
#
|
64
|
+
# Most of the methods in the adapter are useful during migrations. Most
|
65
|
+
# notably, the instance methods provided by SchemaStatement are very useful.
|
66
|
+
class AbstractAdapter
|
67
|
+
ADAPTER_NAME = 'Abstract'.freeze
|
68
|
+
include Quoting, DatabaseStatements, SchemaStatements
|
69
|
+
include DatabaseLimits
|
70
|
+
include QueryCache
|
71
|
+
include ActiveSupport::Callbacks
|
72
|
+
include MonitorMixin
|
73
|
+
include ColumnDumper
|
74
|
+
|
75
|
+
SIMPLE_INT = /\A\d+\z/
|
76
|
+
|
77
|
+
define_callbacks :checkout, :checkin
|
78
|
+
|
79
|
+
attr_accessor :visitor, :pool
|
80
|
+
attr_reader :schema_cache, :owner, :logger
|
81
|
+
alias :in_use? :owner
|
82
|
+
|
83
|
+
def self.type_cast_config_to_integer(config)
|
84
|
+
if config =~ SIMPLE_INT
|
85
|
+
config.to_i
|
86
|
+
else
|
87
|
+
config
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.type_cast_config_to_boolean(config)
|
92
|
+
if config == "false"
|
93
|
+
false
|
94
|
+
else
|
95
|
+
config
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
attr_reader :prepared_statements
|
100
|
+
|
101
|
+
def initialize(connection, logger = nil, pool = nil) #:nodoc:
|
102
|
+
super()
|
103
|
+
|
104
|
+
@connection = connection
|
105
|
+
@owner = nil
|
106
|
+
@instrumenter = ActiveSupport::Notifications.instrumenter
|
107
|
+
@logger = logger
|
108
|
+
@pool = pool
|
109
|
+
@schema_cache = SchemaCache.new self
|
110
|
+
@visitor = nil
|
111
|
+
@prepared_statements = false
|
112
|
+
end
|
113
|
+
|
114
|
+
class BindCollector < Arel::Collectors::Bind
|
115
|
+
def compile(bvs, conn)
|
116
|
+
super(bvs.map { |bv| conn.quote(*bv.reverse) })
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class SQLString < Arel::Collectors::SQLString
|
121
|
+
def compile(bvs, conn)
|
122
|
+
super(bvs)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def collector
|
127
|
+
if prepared_statements
|
128
|
+
SQLString.new
|
129
|
+
else
|
130
|
+
BindCollector.new
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def valid_type?(type)
|
135
|
+
true
|
136
|
+
end
|
137
|
+
|
138
|
+
def schema_creation
|
139
|
+
SchemaCreation.new self
|
140
|
+
end
|
141
|
+
|
142
|
+
def lease
|
143
|
+
synchronize do
|
144
|
+
unless in_use?
|
145
|
+
@owner = Thread.current
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def schema_cache=(cache)
|
151
|
+
cache.connection = self
|
152
|
+
@schema_cache = cache
|
153
|
+
end
|
154
|
+
|
155
|
+
def expire
|
156
|
+
@owner = nil
|
157
|
+
end
|
158
|
+
|
159
|
+
def unprepared_statement
|
160
|
+
old_prepared_statements, @prepared_statements = @prepared_statements, false
|
161
|
+
yield
|
162
|
+
ensure
|
163
|
+
@prepared_statements = old_prepared_statements
|
164
|
+
end
|
165
|
+
|
166
|
+
# Returns the human-readable name of the adapter. Use mixed case - one
|
167
|
+
# can always use downcase if needed.
|
168
|
+
def adapter_name
|
169
|
+
self.class::ADAPTER_NAME
|
170
|
+
end
|
171
|
+
|
172
|
+
# Does this adapter support migrations?
|
173
|
+
def supports_migrations?
|
174
|
+
false
|
175
|
+
end
|
176
|
+
|
177
|
+
# Can this adapter determine the primary key for tables not attached
|
178
|
+
# to an Active Record class, such as join tables?
|
179
|
+
def supports_primary_key?
|
180
|
+
false
|
181
|
+
end
|
182
|
+
|
183
|
+
# Does this adapter support DDL rollbacks in transactions? That is, would
|
184
|
+
# CREATE TABLE or ALTER TABLE get rolled back by a transaction?
|
185
|
+
def supports_ddl_transactions?
|
186
|
+
false
|
187
|
+
end
|
188
|
+
|
189
|
+
def supports_bulk_alter?
|
190
|
+
false
|
191
|
+
end
|
192
|
+
|
193
|
+
# Does this adapter support savepoints?
|
194
|
+
def supports_savepoints?
|
195
|
+
false
|
196
|
+
end
|
197
|
+
|
198
|
+
# Should primary key values be selected from their corresponding
|
199
|
+
# sequence before the insert statement? If true, next_sequence_value
|
200
|
+
# is called before each insert to set the record's primary key.
|
201
|
+
def prefetch_primary_key?(table_name = nil)
|
202
|
+
false
|
203
|
+
end
|
204
|
+
|
205
|
+
# Does this adapter support index sort order?
|
206
|
+
def supports_index_sort_order?
|
207
|
+
false
|
208
|
+
end
|
209
|
+
|
210
|
+
# Does this adapter support partial indices?
|
211
|
+
def supports_partial_index?
|
212
|
+
false
|
213
|
+
end
|
214
|
+
|
215
|
+
# Does this adapter support explain?
|
216
|
+
def supports_explain?
|
217
|
+
false
|
218
|
+
end
|
219
|
+
|
220
|
+
# Does this adapter support setting the isolation level for a transaction?
|
221
|
+
def supports_transaction_isolation?
|
222
|
+
false
|
223
|
+
end
|
224
|
+
|
225
|
+
# Does this adapter support database extensions?
|
226
|
+
def supports_extensions?
|
227
|
+
false
|
228
|
+
end
|
229
|
+
|
230
|
+
# Does this adapter support creating indexes in the same statement as
|
231
|
+
# creating the table?
|
232
|
+
def supports_indexes_in_create?
|
233
|
+
false
|
234
|
+
end
|
235
|
+
|
236
|
+
# Does this adapter support creating foreign key constraints?
|
237
|
+
def supports_foreign_keys?
|
238
|
+
false
|
239
|
+
end
|
240
|
+
|
241
|
+
# Does this adapter support views?
|
242
|
+
def supports_views?
|
243
|
+
false
|
244
|
+
end
|
245
|
+
|
246
|
+
# This is meant to be implemented by the adapters that support extensions
|
247
|
+
def disable_extension(name)
|
248
|
+
end
|
249
|
+
|
250
|
+
# This is meant to be implemented by the adapters that support extensions
|
251
|
+
def enable_extension(name)
|
252
|
+
end
|
253
|
+
|
254
|
+
# A list of extensions, to be filled in by adapters that support them.
|
255
|
+
def extensions
|
256
|
+
[]
|
257
|
+
end
|
258
|
+
|
259
|
+
# A list of index algorithms, to be filled by adapters that support them.
|
260
|
+
def index_algorithms
|
261
|
+
{}
|
262
|
+
end
|
263
|
+
|
264
|
+
# QUOTING ==================================================
|
265
|
+
|
266
|
+
# Returns a bind substitution value given a bind +column+
|
267
|
+
# NOTE: The column param is currently being used by the sqlserver-adapter
|
268
|
+
def substitute_at(column, _unused = 0)
|
269
|
+
Arel::Nodes::BindParam.new
|
270
|
+
end
|
271
|
+
|
272
|
+
# REFERENTIAL INTEGRITY ====================================
|
273
|
+
|
274
|
+
# Override to turn off referential integrity while executing <tt>&block</tt>.
|
275
|
+
def disable_referential_integrity
|
276
|
+
yield
|
277
|
+
end
|
278
|
+
|
279
|
+
# CONNECTION MANAGEMENT ====================================
|
280
|
+
|
281
|
+
# Checks whether the connection to the database is still active. This includes
|
282
|
+
# checking whether the database is actually capable of responding, i.e. whether
|
283
|
+
# the connection isn't stale.
|
284
|
+
def active?
|
285
|
+
end
|
286
|
+
|
287
|
+
# Disconnects from the database if already connected, and establishes a
|
288
|
+
# new connection with the database. Implementors should call super if they
|
289
|
+
# override the default implementation.
|
290
|
+
def reconnect!
|
291
|
+
clear_cache!
|
292
|
+
reset_transaction
|
293
|
+
end
|
294
|
+
|
295
|
+
# Disconnects from the database if already connected. Otherwise, this
|
296
|
+
# method does nothing.
|
297
|
+
def disconnect!
|
298
|
+
clear_cache!
|
299
|
+
reset_transaction
|
300
|
+
end
|
301
|
+
|
302
|
+
# Reset the state of this connection, directing the DBMS to clear
|
303
|
+
# transactions and other connection-related server-side state. Usually a
|
304
|
+
# database-dependent operation.
|
305
|
+
#
|
306
|
+
# The default implementation does nothing; the implementation should be
|
307
|
+
# overridden by concrete adapters.
|
308
|
+
def reset!
|
309
|
+
# this should be overridden by concrete adapters
|
310
|
+
end
|
311
|
+
|
312
|
+
###
|
313
|
+
# Clear any caching the database adapter may be doing, for example
|
314
|
+
# clearing the prepared statement cache. This is database specific.
|
315
|
+
def clear_cache!
|
316
|
+
# this should be overridden by concrete adapters
|
317
|
+
end
|
318
|
+
|
319
|
+
# Returns true if its required to reload the connection between requests for development mode.
|
320
|
+
def requires_reloading?
|
321
|
+
false
|
322
|
+
end
|
323
|
+
|
324
|
+
# Checks whether the connection to the database is still active (i.e. not stale).
|
325
|
+
# This is done under the hood by calling <tt>active?</tt>. If the connection
|
326
|
+
# is no longer active, then this method will reconnect to the database.
|
327
|
+
def verify!(*ignored)
|
328
|
+
reconnect! unless active?
|
329
|
+
end
|
330
|
+
|
331
|
+
# Provides access to the underlying database driver for this adapter. For
|
332
|
+
# example, this method returns a Mysql object in case of MysqlAdapter,
|
333
|
+
# and a PGconn object in case of PostgreSQLAdapter.
|
334
|
+
#
|
335
|
+
# This is useful for when you need to call a proprietary method such as
|
336
|
+
# PostgreSQL's lo_* methods.
|
337
|
+
def raw_connection
|
338
|
+
@connection
|
339
|
+
end
|
340
|
+
|
341
|
+
def create_savepoint(name = nil)
|
342
|
+
end
|
343
|
+
|
344
|
+
def rollback_to_savepoint(name = nil)
|
345
|
+
end
|
346
|
+
|
347
|
+
def release_savepoint(name = nil)
|
348
|
+
end
|
349
|
+
|
350
|
+
def case_sensitive_modifier(node, table_attribute)
|
351
|
+
node
|
352
|
+
end
|
353
|
+
|
354
|
+
def case_sensitive_comparison(table, attribute, column, value)
|
355
|
+
table_attr = table[attribute]
|
356
|
+
value = case_sensitive_modifier(value, table_attr) unless value.nil?
|
357
|
+
table_attr.eq(value)
|
358
|
+
end
|
359
|
+
|
360
|
+
def case_insensitive_comparison(table, attribute, column, value)
|
361
|
+
table[attribute].lower.eq(table.lower(value))
|
362
|
+
end
|
363
|
+
|
364
|
+
def current_savepoint_name
|
365
|
+
current_transaction.savepoint_name
|
366
|
+
end
|
367
|
+
|
368
|
+
# Check the connection back in to the connection pool
|
369
|
+
def close
|
370
|
+
pool.checkin self
|
371
|
+
end
|
372
|
+
|
373
|
+
def type_map # :nodoc:
|
374
|
+
@type_map ||= Type::TypeMap.new.tap do |mapping|
|
375
|
+
initialize_type_map(mapping)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
def new_column(name, default, cast_type, sql_type = nil, null = true)
|
380
|
+
Column.new(name, default, cast_type, sql_type, null)
|
381
|
+
end
|
382
|
+
|
383
|
+
def lookup_cast_type(sql_type) # :nodoc:
|
384
|
+
type_map.lookup(sql_type)
|
385
|
+
end
|
386
|
+
|
387
|
+
def column_name_for_operation(operation, node) # :nodoc:
|
388
|
+
node.to_sql
|
389
|
+
end
|
390
|
+
|
391
|
+
protected
|
392
|
+
|
393
|
+
def initialize_type_map(m) # :nodoc:
|
394
|
+
register_class_with_limit m, %r(boolean)i, Type::Boolean
|
395
|
+
register_class_with_limit m, %r(char)i, Type::String
|
396
|
+
register_class_with_limit m, %r(binary)i, Type::Binary
|
397
|
+
register_class_with_limit m, %r(text)i, Type::Text
|
398
|
+
register_class_with_limit m, %r(date)i, Type::Date
|
399
|
+
register_class_with_limit m, %r(time)i, Type::Time
|
400
|
+
register_class_with_limit m, %r(datetime)i, Type::DateTime
|
401
|
+
register_class_with_limit m, %r(float)i, Type::Float
|
402
|
+
register_class_with_limit m, %r(int)i, Type::Integer
|
403
|
+
|
404
|
+
m.alias_type %r(blob)i, 'binary'
|
405
|
+
m.alias_type %r(clob)i, 'text'
|
406
|
+
m.alias_type %r(timestamp)i, 'datetime'
|
407
|
+
m.alias_type %r(numeric)i, 'decimal'
|
408
|
+
m.alias_type %r(number)i, 'decimal'
|
409
|
+
m.alias_type %r(double)i, 'float'
|
410
|
+
|
411
|
+
m.register_type(%r(decimal)i) do |sql_type|
|
412
|
+
scale = extract_scale(sql_type)
|
413
|
+
precision = extract_precision(sql_type)
|
414
|
+
|
415
|
+
if scale == 0
|
416
|
+
# FIXME: Remove this class as well
|
417
|
+
Type::DecimalWithoutScale.new(precision: precision)
|
418
|
+
else
|
419
|
+
Type::Decimal.new(precision: precision, scale: scale)
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
def reload_type_map # :nodoc:
|
425
|
+
type_map.clear
|
426
|
+
initialize_type_map(type_map)
|
427
|
+
end
|
428
|
+
|
429
|
+
def register_class_with_limit(mapping, key, klass) # :nodoc:
|
430
|
+
mapping.register_type(key) do |*args|
|
431
|
+
limit = extract_limit(args.last)
|
432
|
+
klass.new(limit: limit)
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
def extract_scale(sql_type) # :nodoc:
|
437
|
+
case sql_type
|
438
|
+
when /\((\d+)\)/ then 0
|
439
|
+
when /\((\d+)(,(\d+))\)/ then $3.to_i
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
def extract_precision(sql_type) # :nodoc:
|
444
|
+
$1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
|
445
|
+
end
|
446
|
+
|
447
|
+
def extract_limit(sql_type) # :nodoc:
|
448
|
+
$1.to_i if sql_type =~ /\((.*)\)/
|
449
|
+
end
|
450
|
+
|
451
|
+
def translate_exception_class(e, sql)
|
452
|
+
message = "#{e.class.name}: #{e.message}: #{sql}"
|
453
|
+
@logger.error message if @logger
|
454
|
+
exception = translate_exception(e, message)
|
455
|
+
exception.set_backtrace e.backtrace
|
456
|
+
exception
|
457
|
+
end
|
458
|
+
|
459
|
+
def log(sql, name = "SQL", binds = [], statement_name = nil)
|
460
|
+
@instrumenter.instrument(
|
461
|
+
"sql.active_record",
|
462
|
+
:sql => sql,
|
463
|
+
:name => name,
|
464
|
+
:connection_id => object_id,
|
465
|
+
:statement_name => statement_name,
|
466
|
+
:binds => binds) { yield }
|
467
|
+
rescue => e
|
468
|
+
raise translate_exception_class(e, sql)
|
469
|
+
end
|
470
|
+
|
471
|
+
def translate_exception(exception, message)
|
472
|
+
# override in derived class
|
473
|
+
ActiveRecord::StatementInvalid.new(message, exception)
|
474
|
+
end
|
475
|
+
|
476
|
+
def without_prepared_statement?(binds)
|
477
|
+
!prepared_statements || binds.empty?
|
478
|
+
end
|
479
|
+
|
480
|
+
def column_for(table_name, column_name) # :nodoc:
|
481
|
+
column_name = column_name.to_s
|
482
|
+
columns(table_name).detect { |c| c.name == column_name } ||
|
483
|
+
raise(ActiveRecordError, "No such column: #{table_name}.#{column_name}")
|
484
|
+
end
|
485
|
+
end
|
486
|
+
end
|
487
|
+
end
|