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.

Files changed (221) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1372 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +218 -0
  5. data/examples/performance.rb +184 -0
  6. data/examples/simple.rb +14 -0
  7. data/lib/active_record.rb +173 -0
  8. data/lib/active_record/aggregations.rb +266 -0
  9. data/lib/active_record/association_relation.rb +22 -0
  10. data/lib/active_record/associations.rb +1724 -0
  11. data/lib/active_record/associations/alias_tracker.rb +87 -0
  12. data/lib/active_record/associations/association.rb +253 -0
  13. data/lib/active_record/associations/association_scope.rb +194 -0
  14. data/lib/active_record/associations/belongs_to_association.rb +111 -0
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +40 -0
  16. data/lib/active_record/associations/builder/association.rb +149 -0
  17. data/lib/active_record/associations/builder/belongs_to.rb +116 -0
  18. data/lib/active_record/associations/builder/collection_association.rb +91 -0
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +124 -0
  20. data/lib/active_record/associations/builder/has_many.rb +15 -0
  21. data/lib/active_record/associations/builder/has_one.rb +23 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +38 -0
  23. data/lib/active_record/associations/collection_association.rb +634 -0
  24. data/lib/active_record/associations/collection_proxy.rb +1027 -0
  25. data/lib/active_record/associations/has_many_association.rb +184 -0
  26. data/lib/active_record/associations/has_many_through_association.rb +238 -0
  27. data/lib/active_record/associations/has_one_association.rb +105 -0
  28. data/lib/active_record/associations/has_one_through_association.rb +36 -0
  29. data/lib/active_record/associations/join_dependency.rb +282 -0
  30. data/lib/active_record/associations/join_dependency/join_association.rb +122 -0
  31. data/lib/active_record/associations/join_dependency/join_base.rb +22 -0
  32. data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
  33. data/lib/active_record/associations/preloader.rb +203 -0
  34. data/lib/active_record/associations/preloader/association.rb +162 -0
  35. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  36. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  37. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  38. data/lib/active_record/associations/preloader/has_many_through.rb +19 -0
  39. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  40. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  41. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  42. data/lib/active_record/associations/preloader/through_association.rb +96 -0
  43. data/lib/active_record/associations/singular_association.rb +86 -0
  44. data/lib/active_record/associations/through_association.rb +96 -0
  45. data/lib/active_record/attribute.rb +149 -0
  46. data/lib/active_record/attribute_assignment.rb +212 -0
  47. data/lib/active_record/attribute_decorators.rb +66 -0
  48. data/lib/active_record/attribute_methods.rb +439 -0
  49. data/lib/active_record/attribute_methods/before_type_cast.rb +71 -0
  50. data/lib/active_record/attribute_methods/dirty.rb +181 -0
  51. data/lib/active_record/attribute_methods/primary_key.rb +128 -0
  52. data/lib/active_record/attribute_methods/query.rb +40 -0
  53. data/lib/active_record/attribute_methods/read.rb +103 -0
  54. data/lib/active_record/attribute_methods/serialization.rb +70 -0
  55. data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -0
  56. data/lib/active_record/attribute_methods/write.rb +83 -0
  57. data/lib/active_record/attribute_set.rb +77 -0
  58. data/lib/active_record/attribute_set/builder.rb +86 -0
  59. data/lib/active_record/attributes.rb +139 -0
  60. data/lib/active_record/autosave_association.rb +439 -0
  61. data/lib/active_record/base.rb +317 -0
  62. data/lib/active_record/callbacks.rb +313 -0
  63. data/lib/active_record/coders/json.rb +13 -0
  64. data/lib/active_record/coders/yaml_column.rb +38 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +659 -0
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +67 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +373 -0
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -0
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +133 -0
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +574 -0
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +991 -0
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +219 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +487 -0
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +883 -0
  78. data/lib/active_record/connection_adapters/column.rb +82 -0
  79. data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
  80. data/lib/active_record/connection_adapters/mysql2_adapter.rb +282 -0
  81. data/lib/active_record/connection_adapters/mysql_adapter.rb +491 -0
  82. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +99 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +97 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  111. data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
  112. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +588 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +754 -0
  117. data/lib/active_record/connection_adapters/schema_cache.rb +94 -0
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +628 -0
  119. data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
  120. data/lib/active_record/connection_handling.rb +132 -0
  121. data/lib/active_record/core.rb +566 -0
  122. data/lib/active_record/counter_cache.rb +175 -0
  123. data/lib/active_record/dynamic_matchers.rb +140 -0
  124. data/lib/active_record/enum.rb +198 -0
  125. data/lib/active_record/errors.rb +252 -0
  126. data/lib/active_record/explain.rb +38 -0
  127. data/lib/active_record/explain_registry.rb +30 -0
  128. data/lib/active_record/explain_subscriber.rb +29 -0
  129. data/lib/active_record/fixture_set/file.rb +56 -0
  130. data/lib/active_record/fixtures.rb +1007 -0
  131. data/lib/active_record/gem_version.rb +15 -0
  132. data/lib/active_record/inheritance.rb +247 -0
  133. data/lib/active_record/integration.rb +113 -0
  134. data/lib/active_record/locale/en.yml +47 -0
  135. data/lib/active_record/locking/optimistic.rb +204 -0
  136. data/lib/active_record/locking/pessimistic.rb +77 -0
  137. data/lib/active_record/log_subscriber.rb +75 -0
  138. data/lib/active_record/migration.rb +1051 -0
  139. data/lib/active_record/migration/command_recorder.rb +197 -0
  140. data/lib/active_record/migration/join_table.rb +15 -0
  141. data/lib/active_record/model_schema.rb +340 -0
  142. data/lib/active_record/nested_attributes.rb +548 -0
  143. data/lib/active_record/no_touching.rb +52 -0
  144. data/lib/active_record/null_relation.rb +81 -0
  145. data/lib/active_record/persistence.rb +532 -0
  146. data/lib/active_record/query_cache.rb +56 -0
  147. data/lib/active_record/querying.rb +68 -0
  148. data/lib/active_record/railtie.rb +162 -0
  149. data/lib/active_record/railties/console_sandbox.rb +5 -0
  150. data/lib/active_record/railties/controller_runtime.rb +50 -0
  151. data/lib/active_record/railties/databases.rake +391 -0
  152. data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
  153. data/lib/active_record/readonly_attributes.rb +23 -0
  154. data/lib/active_record/reflection.rb +881 -0
  155. data/lib/active_record/relation.rb +681 -0
  156. data/lib/active_record/relation/batches.rb +138 -0
  157. data/lib/active_record/relation/calculations.rb +403 -0
  158. data/lib/active_record/relation/delegation.rb +140 -0
  159. data/lib/active_record/relation/finder_methods.rb +528 -0
  160. data/lib/active_record/relation/merger.rb +170 -0
  161. data/lib/active_record/relation/predicate_builder.rb +126 -0
  162. data/lib/active_record/relation/predicate_builder/array_handler.rb +47 -0
  163. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  164. data/lib/active_record/relation/query_methods.rb +1176 -0
  165. data/lib/active_record/relation/spawn_methods.rb +75 -0
  166. data/lib/active_record/result.rb +131 -0
  167. data/lib/active_record/runtime_registry.rb +22 -0
  168. data/lib/active_record/sanitization.rb +191 -0
  169. data/lib/active_record/schema.rb +64 -0
  170. data/lib/active_record/schema_dumper.rb +251 -0
  171. data/lib/active_record/schema_migration.rb +56 -0
  172. data/lib/active_record/scoping.rb +87 -0
  173. data/lib/active_record/scoping/default.rb +134 -0
  174. data/lib/active_record/scoping/named.rb +164 -0
  175. data/lib/active_record/serialization.rb +22 -0
  176. data/lib/active_record/serializers/xml_serializer.rb +193 -0
  177. data/lib/active_record/statement_cache.rb +111 -0
  178. data/lib/active_record/store.rb +205 -0
  179. data/lib/active_record/tasks/database_tasks.rb +296 -0
  180. data/lib/active_record/tasks/mysql_database_tasks.rb +145 -0
  181. data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
  182. data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
  183. data/lib/active_record/timestamp.rb +121 -0
  184. data/lib/active_record/transactions.rb +417 -0
  185. data/lib/active_record/translation.rb +22 -0
  186. data/lib/active_record/type.rb +23 -0
  187. data/lib/active_record/type/big_integer.rb +13 -0
  188. data/lib/active_record/type/binary.rb +50 -0
  189. data/lib/active_record/type/boolean.rb +30 -0
  190. data/lib/active_record/type/date.rb +46 -0
  191. data/lib/active_record/type/date_time.rb +43 -0
  192. data/lib/active_record/type/decimal.rb +40 -0
  193. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  194. data/lib/active_record/type/decorator.rb +14 -0
  195. data/lib/active_record/type/float.rb +19 -0
  196. data/lib/active_record/type/hash_lookup_type_map.rb +17 -0
  197. data/lib/active_record/type/integer.rb +55 -0
  198. data/lib/active_record/type/mutable.rb +16 -0
  199. data/lib/active_record/type/numeric.rb +36 -0
  200. data/lib/active_record/type/serialized.rb +56 -0
  201. data/lib/active_record/type/string.rb +36 -0
  202. data/lib/active_record/type/text.rb +11 -0
  203. data/lib/active_record/type/time.rb +26 -0
  204. data/lib/active_record/type/time_value.rb +38 -0
  205. data/lib/active_record/type/type_map.rb +64 -0
  206. data/lib/active_record/type/unsigned_integer.rb +15 -0
  207. data/lib/active_record/type/value.rb +101 -0
  208. data/lib/active_record/validations.rb +90 -0
  209. data/lib/active_record/validations/associated.rb +51 -0
  210. data/lib/active_record/validations/presence.rb +67 -0
  211. data/lib/active_record/validations/uniqueness.rb +229 -0
  212. data/lib/active_record/version.rb +8 -0
  213. data/lib/rails/generators/active_record.rb +17 -0
  214. data/lib/rails/generators/active_record/migration.rb +18 -0
  215. data/lib/rails/generators/active_record/migration/migration_generator.rb +70 -0
  216. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +22 -0
  217. data/lib/rails/generators/active_record/migration/templates/migration.rb +45 -0
  218. data/lib/rails/generators/active_record/model/model_generator.rb +52 -0
  219. data/lib/rails/generators/active_record/model/templates/model.rb +10 -0
  220. data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
  221. metadata +309 -0
@@ -0,0 +1,67 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters # :nodoc:
3
+ module DatabaseLimits
4
+
5
+ # Returns the maximum length of a table alias.
6
+ def table_alias_length
7
+ 255
8
+ end
9
+
10
+ # Returns the maximum length of a column name.
11
+ def column_name_length
12
+ 64
13
+ end
14
+
15
+ # Returns the maximum length of a table name.
16
+ def table_name_length
17
+ 64
18
+ end
19
+
20
+ # Returns the maximum allowed length for an index name. This
21
+ # limit is enforced by rails and Is less than or equal to
22
+ # <tt>index_name_length</tt>. The gap between
23
+ # <tt>index_name_length</tt> is to allow internal rails
24
+ # operations to use prefixes in temporary operations.
25
+ def allowed_index_name_length
26
+ index_name_length
27
+ end
28
+
29
+ # Returns the maximum length of an index name.
30
+ def index_name_length
31
+ 64
32
+ end
33
+
34
+ # Returns the maximum number of columns per table.
35
+ def columns_per_table
36
+ 1024
37
+ end
38
+
39
+ # Returns the maximum number of indexes per table.
40
+ def indexes_per_table
41
+ 16
42
+ end
43
+
44
+ # Returns the maximum number of columns in a multicolumn index.
45
+ def columns_per_multicolumn_index
46
+ 16
47
+ end
48
+
49
+ # Returns the maximum number of elements in an IN (x,y,z) clause.
50
+ # nil means no limit.
51
+ def in_clause_length
52
+ nil
53
+ end
54
+
55
+ # Returns the maximum length of an SQL query.
56
+ def sql_query_length
57
+ 1048575
58
+ end
59
+
60
+ # Returns maximum number of joins in a single query.
61
+ def joins_per_query
62
+ 256
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,373 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters # :nodoc:
3
+ module DatabaseStatements
4
+ def initialize
5
+ super
6
+ reset_transaction
7
+ end
8
+
9
+ # Converts an arel AST to SQL
10
+ def to_sql(arel, binds = [])
11
+ if arel.respond_to?(:ast)
12
+ collected = visitor.accept(arel.ast, collector)
13
+ collected.compile(binds.dup, self)
14
+ else
15
+ arel
16
+ end
17
+ end
18
+
19
+ # This is used in the StatementCache object. It returns an object that
20
+ # can be used to query the database repeatedly.
21
+ def cacheable_query(arel) # :nodoc:
22
+ if prepared_statements
23
+ ActiveRecord::StatementCache.query visitor, arel.ast
24
+ else
25
+ ActiveRecord::StatementCache.partial_query visitor, arel.ast, collector
26
+ end
27
+ end
28
+
29
+ # Returns an ActiveRecord::Result instance.
30
+ def select_all(arel, name = nil, binds = [])
31
+ arel, binds = binds_from_relation arel, binds
32
+ select(to_sql(arel, binds), name, binds)
33
+ end
34
+
35
+ # Returns a record hash with the column names as keys and column values
36
+ # as values.
37
+ def select_one(arel, name = nil, binds = [])
38
+ select_all(arel, name, binds).first
39
+ end
40
+
41
+ # Returns a single value from a record
42
+ def select_value(arel, name = nil, binds = [])
43
+ if result = select_one(arel, name, binds)
44
+ result.values.first
45
+ end
46
+ end
47
+
48
+ # Returns an array of the values of the first column in a select:
49
+ # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
50
+ def select_values(arel, name = nil)
51
+ arel, binds = binds_from_relation arel, []
52
+ select_rows(to_sql(arel, binds), name, binds).map(&:first)
53
+ end
54
+
55
+ # Returns an array of arrays containing the field values.
56
+ # Order is the same as that returned by +columns+.
57
+ def select_rows(sql, name = nil, binds = [])
58
+ end
59
+ undef_method :select_rows
60
+
61
+ # Executes the SQL statement in the context of this connection.
62
+ def execute(sql, name = nil)
63
+ end
64
+ undef_method :execute
65
+
66
+ # Executes +sql+ statement in the context of this connection using
67
+ # +binds+ as the bind substitutes. +name+ is logged along with
68
+ # the executed +sql+ statement.
69
+ def exec_query(sql, name = 'SQL', binds = [])
70
+ end
71
+
72
+ # Executes insert +sql+ statement in the context of this connection using
73
+ # +binds+ as the bind substitutes. +name+ is logged along with
74
+ # the executed +sql+ statement.
75
+ def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
76
+ exec_query(sql, name, binds)
77
+ end
78
+
79
+ # Executes delete +sql+ statement in the context of this connection using
80
+ # +binds+ as the bind substitutes. +name+ is logged along with
81
+ # the executed +sql+ statement.
82
+ def exec_delete(sql, name, binds)
83
+ exec_query(sql, name, binds)
84
+ end
85
+
86
+ # Executes the truncate statement.
87
+ def truncate(table_name, name = nil)
88
+ raise NotImplementedError
89
+ end
90
+
91
+ # Executes update +sql+ statement in the context of this connection using
92
+ # +binds+ as the bind substitutes. +name+ is logged along with
93
+ # the executed +sql+ statement.
94
+ def exec_update(sql, name, binds)
95
+ exec_query(sql, name, binds)
96
+ end
97
+
98
+ # Returns the last auto-generated ID from the affected table.
99
+ #
100
+ # +id_value+ will be returned unless the value is nil, in
101
+ # which case the database will attempt to calculate the last inserted
102
+ # id and return that value.
103
+ #
104
+ # If the next id was calculated in advance (as in Oracle), it should be
105
+ # passed in as +id_value+.
106
+ def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
107
+ sql, binds = sql_for_insert(to_sql(arel, binds), pk, id_value, sequence_name, binds)
108
+ value = exec_insert(sql, name, binds, pk, sequence_name)
109
+ id_value || last_inserted_id(value)
110
+ end
111
+
112
+ # Executes the update statement and returns the number of rows affected.
113
+ def update(arel, name = nil, binds = [])
114
+ exec_update(to_sql(arel, binds), name, binds)
115
+ end
116
+
117
+ # Executes the delete statement and returns the number of rows affected.
118
+ def delete(arel, name = nil, binds = [])
119
+ exec_delete(to_sql(arel, binds), name, binds)
120
+ end
121
+
122
+ # Returns +true+ when the connection adapter supports prepared statement
123
+ # caching, otherwise returns +false+
124
+ def supports_statement_cache?
125
+ false
126
+ end
127
+
128
+ # Runs the given block in a database transaction, and returns the result
129
+ # of the block.
130
+ #
131
+ # == Nested transactions support
132
+ #
133
+ # Most databases don't support true nested transactions. At the time of
134
+ # writing, the only database that supports true nested transactions that
135
+ # we're aware of, is MS-SQL.
136
+ #
137
+ # In order to get around this problem, #transaction will emulate the effect
138
+ # of nested transactions, by using savepoints:
139
+ # http://dev.mysql.com/doc/refman/5.0/en/savepoint.html
140
+ # Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
141
+ # supports savepoints.
142
+ #
143
+ # It is safe to call this method if a database transaction is already open,
144
+ # i.e. if #transaction is called within another #transaction block. In case
145
+ # of a nested call, #transaction will behave as follows:
146
+ #
147
+ # - The block will be run without doing anything. All database statements
148
+ # that happen within the block are effectively appended to the already
149
+ # open database transaction.
150
+ # - However, if +:requires_new+ is set, the block will be wrapped in a
151
+ # database savepoint acting as a sub-transaction.
152
+ #
153
+ # === Caveats
154
+ #
155
+ # MySQL doesn't support DDL transactions. If you perform a DDL operation,
156
+ # then any created savepoints will be automatically released. For example,
157
+ # if you've created a savepoint, then you execute a CREATE TABLE statement,
158
+ # then the savepoint that was created will be automatically released.
159
+ #
160
+ # This means that, on MySQL, you shouldn't execute DDL operations inside
161
+ # a #transaction call that you know might create a savepoint. Otherwise,
162
+ # #transaction will raise exceptions when it tries to release the
163
+ # already-automatically-released savepoints:
164
+ #
165
+ # Model.connection.transaction do # BEGIN
166
+ # Model.connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
167
+ # Model.connection.create_table(...)
168
+ # # active_record_1 now automatically released
169
+ # end # RELEASE SAVEPOINT active_record_1 <--- BOOM! database error!
170
+ # end
171
+ #
172
+ # == Transaction isolation
173
+ #
174
+ # If your database supports setting the isolation level for a transaction, you can set
175
+ # it like so:
176
+ #
177
+ # Post.transaction(isolation: :serializable) do
178
+ # # ...
179
+ # end
180
+ #
181
+ # Valid isolation levels are:
182
+ #
183
+ # * <tt>:read_uncommitted</tt>
184
+ # * <tt>:read_committed</tt>
185
+ # * <tt>:repeatable_read</tt>
186
+ # * <tt>:serializable</tt>
187
+ #
188
+ # You should consult the documentation for your database to understand the
189
+ # semantics of these different levels:
190
+ #
191
+ # * http://www.postgresql.org/docs/9.1/static/transaction-iso.html
192
+ # * https://dev.mysql.com/doc/refman/5.0/en/set-transaction.html
193
+ #
194
+ # An <tt>ActiveRecord::TransactionIsolationError</tt> will be raised if:
195
+ #
196
+ # * The adapter does not support setting the isolation level
197
+ # * You are joining an existing open transaction
198
+ # * You are creating a nested (savepoint) transaction
199
+ #
200
+ # The mysql, mysql2 and postgresql adapters support setting the transaction
201
+ # isolation level. However, support is disabled for MySQL versions below 5,
202
+ # because they are affected by a bug[http://bugs.mysql.com/bug.php?id=39170]
203
+ # which means the isolation level gets persisted outside the transaction.
204
+ def transaction(options = {})
205
+ options.assert_valid_keys :requires_new, :joinable, :isolation
206
+
207
+ if !options[:requires_new] && current_transaction.joinable?
208
+ if options[:isolation]
209
+ raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
210
+ end
211
+ yield
212
+ else
213
+ transaction_manager.within_new_transaction(options) { yield }
214
+ end
215
+ rescue ActiveRecord::Rollback
216
+ # rollbacks are silently swallowed
217
+ end
218
+
219
+ attr_reader :transaction_manager #:nodoc:
220
+
221
+ delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction, :commit_transaction, :rollback_transaction, to: :transaction_manager
222
+
223
+ def transaction_open?
224
+ current_transaction.open?
225
+ end
226
+
227
+ def reset_transaction #:nodoc:
228
+ @transaction_manager = TransactionManager.new(self)
229
+ end
230
+
231
+ # Register a record with the current transaction so that its after_commit and after_rollback callbacks
232
+ # can be called.
233
+ def add_transaction_record(record)
234
+ current_transaction.add_record(record)
235
+ end
236
+
237
+ # Begins the transaction (and turns off auto-committing).
238
+ def begin_db_transaction() end
239
+
240
+ def transaction_isolation_levels
241
+ {
242
+ read_uncommitted: "READ UNCOMMITTED",
243
+ read_committed: "READ COMMITTED",
244
+ repeatable_read: "REPEATABLE READ",
245
+ serializable: "SERIALIZABLE"
246
+ }
247
+ end
248
+
249
+ # Begins the transaction with the isolation level set. Raises an error by
250
+ # default; adapters that support setting the isolation level should implement
251
+ # this method.
252
+ def begin_isolated_db_transaction(isolation)
253
+ raise ActiveRecord::TransactionIsolationError, "adapter does not support setting transaction isolation"
254
+ end
255
+
256
+ # Commits the transaction (and turns on auto-committing).
257
+ def commit_db_transaction() end
258
+
259
+ # Rolls back the transaction (and turns on auto-committing). Must be
260
+ # done if the transaction block raises an exception or returns false.
261
+ def rollback_db_transaction() end
262
+
263
+ def default_sequence_name(table, column)
264
+ nil
265
+ end
266
+
267
+ # Set the sequence to the max value of the table's column.
268
+ def reset_sequence!(table, column, sequence = nil)
269
+ # Do nothing by default. Implement for PostgreSQL, Oracle, ...
270
+ end
271
+
272
+ # Inserts the given fixture into the table. Overridden in adapters that require
273
+ # something beyond a simple insert (eg. Oracle).
274
+ def insert_fixture(fixture, table_name)
275
+ columns = schema_cache.columns_hash(table_name)
276
+
277
+ key_list = []
278
+ value_list = fixture.map do |name, value|
279
+ key_list << quote_column_name(name)
280
+ quote(value, columns[name])
281
+ end
282
+
283
+ execute "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(', ')}) VALUES (#{value_list.join(', ')})", 'Fixture Insert'
284
+ end
285
+
286
+ def empty_insert_statement_value
287
+ "DEFAULT VALUES"
288
+ end
289
+
290
+ # Sanitizes the given LIMIT parameter in order to prevent SQL injection.
291
+ #
292
+ # The +limit+ may be anything that can evaluate to a string via #to_s. It
293
+ # should look like an integer, or a comma-delimited list of integers, or
294
+ # an Arel SQL literal.
295
+ #
296
+ # Returns Integer and Arel::Nodes::SqlLiteral limits as is.
297
+ # Returns the sanitized limit parameter, either as an integer, or as a
298
+ # string which contains a comma-delimited list of integers.
299
+ def sanitize_limit(limit)
300
+ if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral)
301
+ limit
302
+ elsif limit.to_s.include?(',')
303
+ Arel.sql limit.to_s.split(',').map{ |i| Integer(i) }.join(',')
304
+ else
305
+ Integer(limit)
306
+ end
307
+ end
308
+
309
+ # The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
310
+ # on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
311
+ # an UPDATE statement, so in the MySQL adapters we redefine this to do that.
312
+ def join_to_update(update, select) #:nodoc:
313
+ key = update.key
314
+ subselect = subquery_for(key, select)
315
+
316
+ update.where key.in(subselect)
317
+ end
318
+
319
+ def join_to_delete(delete, select, key) #:nodoc:
320
+ subselect = subquery_for(key, select)
321
+
322
+ delete.where key.in(subselect)
323
+ end
324
+
325
+ protected
326
+
327
+ # Returns a subquery for the given key using the join information.
328
+ def subquery_for(key, select)
329
+ subselect = select.clone
330
+ subselect.projections = [key]
331
+ subselect
332
+ end
333
+
334
+ # Returns an ActiveRecord::Result instance.
335
+ def select(sql, name = nil, binds = [])
336
+ exec_query(sql, name, binds)
337
+ end
338
+
339
+
340
+ # Returns the last auto-generated ID from the affected table.
341
+ def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
342
+ execute(sql, name)
343
+ id_value
344
+ end
345
+
346
+ # Executes the update statement and returns the number of rows affected.
347
+ def update_sql(sql, name = nil)
348
+ execute(sql, name)
349
+ end
350
+
351
+ # Executes the delete statement and returns the number of rows affected.
352
+ def delete_sql(sql, name = nil)
353
+ update_sql(sql, name)
354
+ end
355
+
356
+ def sql_for_insert(sql, pk, id_value, sequence_name, binds)
357
+ [sql, binds]
358
+ end
359
+
360
+ def last_inserted_id(result)
361
+ row = result.rows.first
362
+ row && row.first
363
+ end
364
+
365
+ def binds_from_relation(relation, binds)
366
+ if relation.is_a?(Relation) && binds.empty?
367
+ relation, binds = relation.arel, relation.bind_values
368
+ end
369
+ [relation, binds]
370
+ end
371
+ end
372
+ end
373
+ end
@@ -0,0 +1,95 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters # :nodoc:
3
+ module QueryCache
4
+ class << self
5
+ def included(base) #:nodoc:
6
+ dirties_query_cache base, :insert, :update, :delete
7
+ end
8
+
9
+ def dirties_query_cache(base, *method_names)
10
+ method_names.each do |method_name|
11
+ base.class_eval <<-end_code, __FILE__, __LINE__ + 1
12
+ def #{method_name}(*)
13
+ clear_query_cache if @query_cache_enabled
14
+ super
15
+ end
16
+ end_code
17
+ end
18
+ end
19
+ end
20
+
21
+ attr_reader :query_cache, :query_cache_enabled
22
+
23
+ def initialize(*)
24
+ super
25
+ @query_cache = Hash.new { |h,sql| h[sql] = {} }
26
+ @query_cache_enabled = false
27
+ end
28
+
29
+ # Enable the query cache within the block.
30
+ def cache
31
+ old, @query_cache_enabled = @query_cache_enabled, true
32
+ yield
33
+ ensure
34
+ @query_cache_enabled = old
35
+ clear_query_cache unless @query_cache_enabled
36
+ end
37
+
38
+ def enable_query_cache!
39
+ @query_cache_enabled = true
40
+ end
41
+
42
+ def disable_query_cache!
43
+ @query_cache_enabled = false
44
+ end
45
+
46
+ # Disable the query cache within the block.
47
+ def uncached
48
+ old, @query_cache_enabled = @query_cache_enabled, false
49
+ yield
50
+ ensure
51
+ @query_cache_enabled = old
52
+ end
53
+
54
+ # Clears the query cache.
55
+ #
56
+ # One reason you may wish to call this method explicitly is between queries
57
+ # that ask the database to randomize results. Otherwise the cache would see
58
+ # the same SQL query and repeatedly return the same result each time, silently
59
+ # undermining the randomness you were expecting.
60
+ def clear_query_cache
61
+ @query_cache.clear
62
+ end
63
+
64
+ def select_all(arel, name = nil, binds = [])
65
+ if @query_cache_enabled && !locked?(arel)
66
+ arel, binds = binds_from_relation arel, binds
67
+ sql = to_sql(arel, binds)
68
+ cache_sql(sql, binds) { super(sql, name, binds) }
69
+ else
70
+ super
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ def cache_sql(sql, binds)
77
+ result =
78
+ if @query_cache[sql].key?(binds)
79
+ ActiveSupport::Notifications.instrument("sql.active_record",
80
+ :sql => sql, :binds => binds, :name => "CACHE", :connection_id => object_id)
81
+ @query_cache[sql][binds]
82
+ else
83
+ @query_cache[sql][binds] = yield
84
+ end
85
+ result.dup
86
+ end
87
+
88
+ # If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such
89
+ # queries should not be cached.
90
+ def locked?(arel)
91
+ arel.respond_to?(:locked) && arel.locked
92
+ end
93
+ end
94
+ end
95
+ end