activerecord 3.2.22.5 → 5.2.8
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 +5 -5
- data/CHANGELOG.md +657 -621
- data/MIT-LICENSE +2 -2
- data/README.rdoc +41 -46
- data/examples/performance.rb +55 -42
- data/examples/simple.rb +6 -5
- data/lib/active_record/aggregations.rb +264 -236
- data/lib/active_record/association_relation.rb +40 -0
- data/lib/active_record/associations/alias_tracker.rb +47 -42
- data/lib/active_record/associations/association.rb +127 -75
- data/lib/active_record/associations/association_scope.rb +126 -92
- data/lib/active_record/associations/belongs_to_association.rb +78 -27
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +9 -4
- data/lib/active_record/associations/builder/association.rb +117 -32
- data/lib/active_record/associations/builder/belongs_to.rb +135 -60
- data/lib/active_record/associations/builder/collection_association.rb +61 -54
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +120 -42
- data/lib/active_record/associations/builder/has_many.rb +10 -64
- data/lib/active_record/associations/builder/has_one.rb +19 -51
- data/lib/active_record/associations/builder/singular_association.rb +28 -18
- data/lib/active_record/associations/collection_association.rb +226 -293
- data/lib/active_record/associations/collection_proxy.rb +1067 -69
- data/lib/active_record/associations/foreign_association.rb +13 -0
- data/lib/active_record/associations/has_many_association.rb +83 -47
- data/lib/active_record/associations/has_many_through_association.rb +98 -65
- data/lib/active_record/associations/has_one_association.rb +57 -20
- data/lib/active_record/associations/has_one_through_association.rb +18 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +48 -126
- data/lib/active_record/associations/join_dependency/join_base.rb +11 -12
- data/lib/active_record/associations/join_dependency/join_part.rb +35 -42
- data/lib/active_record/associations/join_dependency.rb +212 -164
- data/lib/active_record/associations/preloader/association.rb +95 -89
- data/lib/active_record/associations/preloader/through_association.rb +84 -44
- data/lib/active_record/associations/preloader.rb +123 -111
- data/lib/active_record/associations/singular_association.rb +33 -24
- data/lib/active_record/associations/through_association.rb +60 -26
- data/lib/active_record/associations.rb +1759 -1506
- data/lib/active_record/attribute_assignment.rb +60 -193
- data/lib/active_record/attribute_decorators.rb +90 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +55 -8
- data/lib/active_record/attribute_methods/dirty.rb +113 -74
- data/lib/active_record/attribute_methods/primary_key.rb +106 -77
- data/lib/active_record/attribute_methods/query.rb +8 -5
- data/lib/active_record/attribute_methods/read.rb +63 -114
- data/lib/active_record/attribute_methods/serialization.rb +60 -90
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +69 -43
- data/lib/active_record/attribute_methods/write.rb +43 -45
- data/lib/active_record/attribute_methods.rb +366 -149
- data/lib/active_record/attributes.rb +266 -0
- data/lib/active_record/autosave_association.rb +312 -225
- data/lib/active_record/base.rb +114 -505
- data/lib/active_record/callbacks.rb +145 -67
- data/lib/active_record/coders/json.rb +15 -0
- data/lib/active_record/coders/yaml_column.rb +32 -23
- data/lib/active_record/collection_cache_key.rb +53 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +883 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +16 -2
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +350 -200
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +150 -65
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +146 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +477 -284
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +95 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1100 -310
- data/lib/active_record/connection_adapters/abstract/transaction.rb +283 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +450 -118
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +657 -446
- data/lib/active_record/connection_adapters/column.rb +50 -255
- data/lib/active_record/connection_adapters/connection_specification.rb +287 -0
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +59 -210
- data/lib/active_record/connection_adapters/postgresql/column.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +163 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +56 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +111 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +168 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +206 -0
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +774 -0
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +620 -1080
- data/lib/active_record/connection_adapters/schema_cache.rb +85 -36
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +545 -27
- data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
- data/lib/active_record/connection_handling.rb +145 -0
- data/lib/active_record/core.rb +559 -0
- data/lib/active_record/counter_cache.rb +200 -105
- data/lib/active_record/define_callbacks.rb +22 -0
- data/lib/active_record/dynamic_matchers.rb +107 -69
- data/lib/active_record/enum.rb +244 -0
- data/lib/active_record/errors.rb +245 -60
- data/lib/active_record/explain.rb +35 -71
- data/lib/active_record/explain_registry.rb +32 -0
- data/lib/active_record/explain_subscriber.rb +18 -9
- data/lib/active_record/fixture_set/file.rb +82 -0
- data/lib/active_record/fixtures.rb +418 -275
- data/lib/active_record/gem_version.rb +17 -0
- data/lib/active_record/inheritance.rb +209 -100
- data/lib/active_record/integration.rb +116 -21
- data/lib/active_record/internal_metadata.rb +45 -0
- data/lib/active_record/legacy_yaml_adapter.rb +48 -0
- data/lib/active_record/locale/en.yml +9 -1
- data/lib/active_record/locking/optimistic.rb +107 -94
- data/lib/active_record/locking/pessimistic.rb +20 -8
- data/lib/active_record/log_subscriber.rb +99 -34
- data/lib/active_record/migration/command_recorder.rb +199 -64
- data/lib/active_record/migration/compatibility.rb +217 -0
- data/lib/active_record/migration/join_table.rb +17 -0
- data/lib/active_record/migration.rb +893 -296
- data/lib/active_record/model_schema.rb +328 -175
- data/lib/active_record/nested_attributes.rb +338 -242
- data/lib/active_record/no_touching.rb +58 -0
- data/lib/active_record/null_relation.rb +68 -0
- data/lib/active_record/persistence.rb +557 -170
- data/lib/active_record/query_cache.rb +14 -43
- data/lib/active_record/querying.rb +36 -24
- data/lib/active_record/railtie.rb +147 -52
- data/lib/active_record/railties/console_sandbox.rb +5 -4
- data/lib/active_record/railties/controller_runtime.rb +13 -6
- data/lib/active_record/railties/databases.rake +206 -488
- data/lib/active_record/readonly_attributes.rb +4 -6
- data/lib/active_record/reflection.rb +734 -228
- data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
- data/lib/active_record/relation/batches.rb +249 -52
- data/lib/active_record/relation/calculations.rb +330 -284
- data/lib/active_record/relation/delegation.rb +135 -37
- data/lib/active_record/relation/finder_methods.rb +450 -287
- data/lib/active_record/relation/from_clause.rb +26 -0
- data/lib/active_record/relation/merger.rb +193 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
- data/lib/active_record/relation/predicate_builder.rb +132 -43
- data/lib/active_record/relation/query_attribute.rb +45 -0
- data/lib/active_record/relation/query_methods.rb +1037 -221
- data/lib/active_record/relation/record_fetch_warning.rb +51 -0
- data/lib/active_record/relation/spawn_methods.rb +48 -151
- data/lib/active_record/relation/where_clause.rb +186 -0
- data/lib/active_record/relation/where_clause_factory.rb +34 -0
- data/lib/active_record/relation.rb +451 -359
- data/lib/active_record/result.rb +129 -20
- data/lib/active_record/runtime_registry.rb +24 -0
- data/lib/active_record/sanitization.rb +164 -136
- data/lib/active_record/schema.rb +31 -19
- data/lib/active_record/schema_dumper.rb +154 -107
- data/lib/active_record/schema_migration.rb +56 -0
- data/lib/active_record/scoping/default.rb +108 -98
- data/lib/active_record/scoping/named.rb +125 -112
- data/lib/active_record/scoping.rb +77 -123
- data/lib/active_record/secure_token.rb +40 -0
- data/lib/active_record/serialization.rb +10 -6
- data/lib/active_record/statement_cache.rb +121 -0
- data/lib/active_record/store.rb +175 -16
- data/lib/active_record/suppressor.rb +61 -0
- data/lib/active_record/table_metadata.rb +82 -0
- data/lib/active_record/tasks/database_tasks.rb +337 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +143 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +83 -0
- data/lib/active_record/timestamp.rb +80 -41
- data/lib/active_record/touch_later.rb +64 -0
- data/lib/active_record/transactions.rb +240 -119
- data/lib/active_record/translation.rb +2 -0
- data/lib/active_record/type/adapter_specific_registry.rb +136 -0
- data/lib/active_record/type/date.rb +9 -0
- data/lib/active_record/type/date_time.rb +9 -0
- data/lib/active_record/type/decimal_without_scale.rb +15 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
- data/lib/active_record/type/internal/timezone.rb +17 -0
- data/lib/active_record/type/json.rb +30 -0
- data/lib/active_record/type/serialized.rb +71 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +21 -0
- data/lib/active_record/type/type_map.rb +62 -0
- data/lib/active_record/type/unsigned_integer.rb +17 -0
- data/lib/active_record/type.rb +79 -0
- data/lib/active_record/type_caster/connection.rb +33 -0
- data/lib/active_record/type_caster/map.rb +23 -0
- data/lib/active_record/type_caster.rb +9 -0
- data/lib/active_record/validations/absence.rb +25 -0
- data/lib/active_record/validations/associated.rb +35 -18
- data/lib/active_record/validations/length.rb +26 -0
- data/lib/active_record/validations/presence.rb +68 -0
- data/lib/active_record/validations/uniqueness.rb +133 -75
- data/lib/active_record/validations.rb +53 -43
- data/lib/active_record/version.rb +7 -7
- data/lib/active_record.rb +89 -57
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +61 -8
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +46 -0
- data/lib/rails/generators/active_record/migration.rb +28 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +23 -22
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +13 -0
- data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +1 -1
- data/lib/rails/generators/active_record.rb +10 -16
- metadata +141 -62
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
- data/lib/active_record/associations/join_helper.rb +0 -55
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
- data/lib/active_record/associations/preloader/collection_association.rb +0 -24
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/associations/preloader/has_many.rb +0 -17
- data/lib/active_record/associations/preloader/has_many_through.rb +0 -15
- data/lib/active_record/associations/preloader/has_one.rb +0 -23
- data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
- data/lib/active_record/associations/preloader/singular_association.rb +0 -21
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
- data/lib/active_record/serializers/xml_serializer.rb +0 -203
- data/lib/active_record/session_store.rb +0 -360
- data/lib/active_record/test_case.rb +0 -73
- data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -34
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
- data/lib/rails/generators/active_record/model/templates/model.rb +0 -12
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,125 +1,187 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters # :nodoc:
|
3
5
|
module DatabaseStatements
|
6
|
+
def initialize
|
7
|
+
super
|
8
|
+
reset_transaction
|
9
|
+
end
|
10
|
+
|
4
11
|
# Converts an arel AST to SQL
|
5
|
-
def to_sql(
|
6
|
-
|
7
|
-
|
8
|
-
|
12
|
+
def to_sql(arel_or_sql_string, binds = [])
|
13
|
+
sql, _ = to_sql_and_binds(arel_or_sql_string, binds)
|
14
|
+
sql
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_sql_and_binds(arel_or_sql_string, binds = []) # :nodoc:
|
18
|
+
if arel_or_sql_string.respond_to?(:ast)
|
19
|
+
unless binds.empty?
|
20
|
+
raise "Passing bind parameters with an arel AST is forbidden. " \
|
21
|
+
"The values must be stored on the AST directly"
|
22
|
+
end
|
23
|
+
|
24
|
+
if prepared_statements
|
25
|
+
sql, binds = visitor.accept(arel_or_sql_string.ast, collector).value
|
26
|
+
|
27
|
+
if binds.length > bind_params_length
|
28
|
+
unprepared_statement do
|
29
|
+
sql, binds = to_sql_and_binds(arel_or_sql_string)
|
30
|
+
visitor.preparable = false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
else
|
34
|
+
sql = visitor.accept(arel_or_sql_string.ast, collector).value
|
9
35
|
end
|
36
|
+
[sql.freeze, binds]
|
37
|
+
else
|
38
|
+
visitor.preparable = false if prepared_statements
|
39
|
+
[arel_or_sql_string.dup.freeze, binds]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
private :to_sql_and_binds
|
43
|
+
|
44
|
+
# This is used in the StatementCache object. It returns an object that
|
45
|
+
# can be used to query the database repeatedly.
|
46
|
+
def cacheable_query(klass, arel) # :nodoc:
|
47
|
+
if prepared_statements
|
48
|
+
sql, binds = visitor.accept(arel.ast, collector).value
|
49
|
+
query = klass.query(sql)
|
10
50
|
else
|
11
|
-
|
51
|
+
collector = PartialQueryCollector.new
|
52
|
+
parts, binds = visitor.accept(arel.ast, collector).value
|
53
|
+
query = klass.partial_query(parts)
|
12
54
|
end
|
55
|
+
[query, binds]
|
13
56
|
end
|
14
57
|
|
15
|
-
# Returns an
|
16
|
-
|
17
|
-
|
18
|
-
|
58
|
+
# Returns an ActiveRecord::Result instance.
|
59
|
+
def select_all(arel, name = nil, binds = [], preparable: nil)
|
60
|
+
arel = arel_from_relation(arel)
|
61
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
62
|
+
|
63
|
+
if preparable.nil?
|
64
|
+
preparable = prepared_statements ? visitor.preparable : false
|
65
|
+
end
|
66
|
+
|
67
|
+
if prepared_statements && preparable
|
68
|
+
select_prepared(sql, name, binds)
|
69
|
+
else
|
70
|
+
select(sql, name, binds)
|
71
|
+
end
|
19
72
|
end
|
20
73
|
|
21
74
|
# Returns a record hash with the column names as keys and column values
|
22
75
|
# as values.
|
23
|
-
def select_one(arel, name = nil)
|
24
|
-
|
25
|
-
result.first if result
|
76
|
+
def select_one(arel, name = nil, binds = [])
|
77
|
+
select_all(arel, name, binds).first
|
26
78
|
end
|
27
79
|
|
28
80
|
# Returns a single value from a record
|
29
|
-
def select_value(arel, name = nil)
|
30
|
-
|
31
|
-
result.values.first
|
32
|
-
end
|
81
|
+
def select_value(arel, name = nil, binds = [])
|
82
|
+
single_value_from_rows(select_rows(arel, name, binds))
|
33
83
|
end
|
34
84
|
|
35
85
|
# Returns an array of the values of the first column in a select:
|
36
86
|
# select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
|
37
|
-
def select_values(arel, name = nil)
|
38
|
-
|
39
|
-
result.map { |v| v[0] }
|
87
|
+
def select_values(arel, name = nil, binds = [])
|
88
|
+
select_rows(arel, name, binds).map(&:first)
|
40
89
|
end
|
41
90
|
|
42
91
|
# Returns an array of arrays containing the field values.
|
43
92
|
# Order is the same as that returned by +columns+.
|
44
|
-
def select_rows(
|
93
|
+
def select_rows(arel, name = nil, binds = [])
|
94
|
+
select_all(arel, name, binds).rows
|
95
|
+
end
|
96
|
+
|
97
|
+
def query_value(sql, name = nil) # :nodoc:
|
98
|
+
single_value_from_rows(query(sql, name))
|
99
|
+
end
|
100
|
+
|
101
|
+
def query_values(sql, name = nil) # :nodoc:
|
102
|
+
query(sql, name).map(&:first)
|
45
103
|
end
|
46
|
-
undef_method :select_rows
|
47
104
|
|
48
|
-
|
105
|
+
def query(sql, name = nil) # :nodoc:
|
106
|
+
exec_query(sql, name).rows
|
107
|
+
end
|
108
|
+
|
109
|
+
# Executes the SQL statement in the context of this connection and returns
|
110
|
+
# the raw result from the connection adapter.
|
111
|
+
# Note: depending on your database connector, the result returned by this
|
112
|
+
# method may be manually memory managed. Consider using the exec_query
|
113
|
+
# wrapper instead.
|
49
114
|
def execute(sql, name = nil)
|
115
|
+
raise NotImplementedError
|
50
116
|
end
|
51
|
-
undef_method :execute
|
52
117
|
|
53
118
|
# Executes +sql+ statement in the context of this connection using
|
54
119
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
55
120
|
# the executed +sql+ statement.
|
56
|
-
def exec_query(sql, name =
|
121
|
+
def exec_query(sql, name = "SQL", binds = [], prepare: false)
|
122
|
+
raise NotImplementedError
|
57
123
|
end
|
58
124
|
|
59
125
|
# Executes insert +sql+ statement in the context of this connection using
|
60
|
-
# +binds+ as the bind substitutes. +name+ is
|
126
|
+
# +binds+ as the bind substitutes. +name+ is logged along with
|
61
127
|
# the executed +sql+ statement.
|
62
|
-
def exec_insert(sql, name, binds)
|
128
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
129
|
+
sql, binds = sql_for_insert(sql, pk, nil, sequence_name, binds)
|
63
130
|
exec_query(sql, name, binds)
|
64
131
|
end
|
65
132
|
|
66
133
|
# Executes delete +sql+ statement in the context of this connection using
|
67
|
-
# +binds+ as the bind substitutes. +name+ is
|
134
|
+
# +binds+ as the bind substitutes. +name+ is logged along with
|
68
135
|
# the executed +sql+ statement.
|
69
|
-
def exec_delete(sql, name, binds)
|
136
|
+
def exec_delete(sql, name = nil, binds = [])
|
70
137
|
exec_query(sql, name, binds)
|
71
138
|
end
|
72
139
|
|
140
|
+
# Executes the truncate statement.
|
141
|
+
def truncate(table_name, name = nil)
|
142
|
+
raise NotImplementedError
|
143
|
+
end
|
144
|
+
|
73
145
|
# Executes update +sql+ statement in the context of this connection using
|
74
|
-
# +binds+ as the bind substitutes. +name+ is
|
146
|
+
# +binds+ as the bind substitutes. +name+ is logged along with
|
75
147
|
# the executed +sql+ statement.
|
76
|
-
def exec_update(sql, name, binds)
|
148
|
+
def exec_update(sql, name = nil, binds = [])
|
77
149
|
exec_query(sql, name, binds)
|
78
150
|
end
|
79
151
|
|
80
|
-
#
|
152
|
+
# Executes an INSERT query and returns the new record's ID
|
81
153
|
#
|
82
|
-
# +id_value+ will be returned unless the value is nil
|
154
|
+
# +id_value+ will be returned unless the value is +nil+, in
|
83
155
|
# which case the database will attempt to calculate the last inserted
|
84
156
|
# id and return that value.
|
85
157
|
#
|
86
158
|
# If the next id was calculated in advance (as in Oracle), it should be
|
87
159
|
# passed in as +id_value+.
|
88
160
|
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
89
|
-
sql, binds =
|
90
|
-
value
|
161
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
162
|
+
value = exec_insert(sql, name, binds, pk, sequence_name)
|
91
163
|
id_value || last_inserted_id(value)
|
92
164
|
end
|
165
|
+
alias create insert
|
93
166
|
|
94
167
|
# Executes the update statement and returns the number of rows affected.
|
95
168
|
def update(arel, name = nil, binds = [])
|
96
|
-
|
169
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
170
|
+
exec_update(sql, name, binds)
|
97
171
|
end
|
98
172
|
|
99
173
|
# Executes the delete statement and returns the number of rows affected.
|
100
174
|
def delete(arel, name = nil, binds = [])
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
# Checks whether there is currently no transaction active. This is done
|
105
|
-
# by querying the database driver, and does not use the transaction
|
106
|
-
# house-keeping information recorded by #increment_open_transactions and
|
107
|
-
# friends.
|
108
|
-
#
|
109
|
-
# Returns true if there is no transaction active, false if there is a
|
110
|
-
# transaction active, and nil if this information is unknown.
|
111
|
-
#
|
112
|
-
# Not all adapters supports transaction state introspection. Currently,
|
113
|
-
# only the PostgreSQL adapter supports this.
|
114
|
-
def outside_transaction?
|
115
|
-
nil
|
175
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
176
|
+
exec_delete(sql, name, binds)
|
116
177
|
end
|
117
178
|
|
118
179
|
# Returns +true+ when the connection adapter supports prepared statement
|
119
180
|
# caching, otherwise returns +false+
|
120
|
-
def supports_statement_cache?
|
121
|
-
|
181
|
+
def supports_statement_cache? # :nodoc:
|
182
|
+
true
|
122
183
|
end
|
184
|
+
deprecate :supports_statement_cache?
|
123
185
|
|
124
186
|
# Runs the given block in a database transaction, and returns the result
|
125
187
|
# of the block.
|
@@ -132,8 +194,9 @@ module ActiveRecord
|
|
132
194
|
#
|
133
195
|
# In order to get around this problem, #transaction will emulate the effect
|
134
196
|
# of nested transactions, by using savepoints:
|
135
|
-
#
|
136
|
-
# Savepoints are supported by MySQL and PostgreSQL
|
197
|
+
# https://dev.mysql.com/doc/refman/5.7/en/savepoint.html
|
198
|
+
# Savepoints are supported by MySQL and PostgreSQL. SQLite3 version >= '3.6.8'
|
199
|
+
# supports savepoints.
|
137
200
|
#
|
138
201
|
# It is safe to call this method if a database transaction is already open,
|
139
202
|
# i.e. if #transaction is called within another #transaction block. In case
|
@@ -158,101 +221,110 @@ module ActiveRecord
|
|
158
221
|
# already-automatically-released savepoints:
|
159
222
|
#
|
160
223
|
# Model.connection.transaction do # BEGIN
|
161
|
-
# Model.connection.transaction(:
|
224
|
+
# Model.connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
|
162
225
|
# Model.connection.create_table(...)
|
163
226
|
# # active_record_1 now automatically released
|
164
227
|
# end # RELEASE SAVEPOINT active_record_1 <--- BOOM! database error!
|
165
228
|
# end
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
else
|
202
|
-
rollback_to_savepoint
|
203
|
-
rollback_transaction_records(false)
|
204
|
-
end
|
205
|
-
end
|
206
|
-
raise unless database_transaction_rollback.is_a?(ActiveRecord::Rollback)
|
207
|
-
end
|
208
|
-
ensure
|
209
|
-
@transaction_joinable = last_transaction_joinable
|
210
|
-
|
211
|
-
if outside_transaction?
|
212
|
-
@open_transactions = 0
|
213
|
-
elsif transaction_open
|
214
|
-
decrement_open_transactions
|
215
|
-
begin
|
216
|
-
if open_transactions == 0
|
217
|
-
commit_db_transaction
|
218
|
-
commit_transaction_records
|
219
|
-
else
|
220
|
-
release_savepoint
|
221
|
-
save_point_records = @_current_transaction_records.pop
|
222
|
-
unless save_point_records.blank?
|
223
|
-
@_current_transaction_records.push([]) if @_current_transaction_records.empty?
|
224
|
-
@_current_transaction_records.last.concat(save_point_records)
|
225
|
-
end
|
226
|
-
end
|
227
|
-
rescue Exception => database_transaction_rollback
|
228
|
-
if open_transactions == 0
|
229
|
-
rollback_db_transaction
|
230
|
-
rollback_transaction_records(true)
|
231
|
-
else
|
232
|
-
rollback_to_savepoint
|
233
|
-
rollback_transaction_records(false)
|
234
|
-
end
|
235
|
-
raise
|
229
|
+
#
|
230
|
+
# == Transaction isolation
|
231
|
+
#
|
232
|
+
# If your database supports setting the isolation level for a transaction, you can set
|
233
|
+
# it like so:
|
234
|
+
#
|
235
|
+
# Post.transaction(isolation: :serializable) do
|
236
|
+
# # ...
|
237
|
+
# end
|
238
|
+
#
|
239
|
+
# Valid isolation levels are:
|
240
|
+
#
|
241
|
+
# * <tt>:read_uncommitted</tt>
|
242
|
+
# * <tt>:read_committed</tt>
|
243
|
+
# * <tt>:repeatable_read</tt>
|
244
|
+
# * <tt>:serializable</tt>
|
245
|
+
#
|
246
|
+
# You should consult the documentation for your database to understand the
|
247
|
+
# semantics of these different levels:
|
248
|
+
#
|
249
|
+
# * https://www.postgresql.org/docs/current/static/transaction-iso.html
|
250
|
+
# * https://dev.mysql.com/doc/refman/5.7/en/set-transaction.html
|
251
|
+
#
|
252
|
+
# An ActiveRecord::TransactionIsolationError will be raised if:
|
253
|
+
#
|
254
|
+
# * The adapter does not support setting the isolation level
|
255
|
+
# * You are joining an existing open transaction
|
256
|
+
# * You are creating a nested (savepoint) transaction
|
257
|
+
#
|
258
|
+
# The mysql2 and postgresql adapters support setting the transaction
|
259
|
+
# isolation level.
|
260
|
+
def transaction(requires_new: nil, isolation: nil, joinable: true)
|
261
|
+
if !requires_new && current_transaction.joinable?
|
262
|
+
if isolation
|
263
|
+
raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
|
236
264
|
end
|
265
|
+
yield
|
266
|
+
else
|
267
|
+
transaction_manager.within_new_transaction(isolation: isolation, joinable: joinable) { yield }
|
237
268
|
end
|
269
|
+
rescue ActiveRecord::Rollback
|
270
|
+
# rollbacks are silently swallowed
|
271
|
+
end
|
272
|
+
|
273
|
+
attr_reader :transaction_manager #:nodoc:
|
274
|
+
|
275
|
+
delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction, :commit_transaction, :rollback_transaction, to: :transaction_manager
|
276
|
+
|
277
|
+
def transaction_open?
|
278
|
+
current_transaction.open?
|
279
|
+
end
|
280
|
+
|
281
|
+
def reset_transaction #:nodoc:
|
282
|
+
@transaction_manager = ConnectionAdapters::TransactionManager.new(self)
|
238
283
|
end
|
239
284
|
|
240
285
|
# Register a record with the current transaction so that its after_commit and after_rollback callbacks
|
241
286
|
# can be called.
|
242
287
|
def add_transaction_record(record)
|
243
|
-
|
244
|
-
|
288
|
+
current_transaction.add_record(record)
|
289
|
+
end
|
290
|
+
|
291
|
+
def transaction_state
|
292
|
+
current_transaction.state
|
245
293
|
end
|
246
294
|
|
247
295
|
# Begins the transaction (and turns off auto-committing).
|
248
296
|
def begin_db_transaction() end
|
249
297
|
|
298
|
+
def transaction_isolation_levels
|
299
|
+
{
|
300
|
+
read_uncommitted: "READ UNCOMMITTED",
|
301
|
+
read_committed: "READ COMMITTED",
|
302
|
+
repeatable_read: "REPEATABLE READ",
|
303
|
+
serializable: "SERIALIZABLE"
|
304
|
+
}
|
305
|
+
end
|
306
|
+
|
307
|
+
# Begins the transaction with the isolation level set. Raises an error by
|
308
|
+
# default; adapters that support setting the isolation level should implement
|
309
|
+
# this method.
|
310
|
+
def begin_isolated_db_transaction(isolation)
|
311
|
+
raise ActiveRecord::TransactionIsolationError, "adapter does not support setting transaction isolation"
|
312
|
+
end
|
313
|
+
|
250
314
|
# Commits the transaction (and turns on auto-committing).
|
251
315
|
def commit_db_transaction() end
|
252
316
|
|
253
317
|
# Rolls back the transaction (and turns on auto-committing). Must be
|
254
318
|
# done if the transaction block raises an exception or returns false.
|
255
|
-
def rollback_db_transaction
|
319
|
+
def rollback_db_transaction
|
320
|
+
exec_rollback_db_transaction
|
321
|
+
end
|
322
|
+
|
323
|
+
def exec_rollback_db_transaction() end #:nodoc:
|
324
|
+
|
325
|
+
def rollback_to_savepoint(name = nil)
|
326
|
+
exec_rollback_to_savepoint(name)
|
327
|
+
end
|
256
328
|
|
257
329
|
def default_sequence_name(table, column)
|
258
330
|
nil
|
@@ -265,126 +337,204 @@ module ActiveRecord
|
|
265
337
|
|
266
338
|
# Inserts the given fixture into the table. Overridden in adapters that require
|
267
339
|
# something beyond a simple insert (eg. Oracle).
|
340
|
+
# Most of adapters should implement `insert_fixtures` that leverages bulk SQL insert.
|
341
|
+
# We keep this method to provide fallback
|
342
|
+
# for databases like sqlite that do not support bulk inserts.
|
268
343
|
def insert_fixture(fixture, table_name)
|
344
|
+
fixture = fixture.stringify_keys
|
345
|
+
|
269
346
|
columns = schema_cache.columns_hash(table_name)
|
347
|
+
binds = fixture.map do |name, value|
|
348
|
+
if column = columns[name]
|
349
|
+
type = lookup_cast_type_from_column(column)
|
350
|
+
Relation::QueryAttribute.new(name, value, type)
|
351
|
+
else
|
352
|
+
raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
|
353
|
+
end
|
354
|
+
end
|
270
355
|
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
356
|
+
table = Arel::Table.new(table_name)
|
357
|
+
|
358
|
+
values = binds.map do |bind|
|
359
|
+
value = with_yaml_fallback(bind.value_for_database)
|
360
|
+
[table[bind.name], value]
|
275
361
|
end
|
276
362
|
|
277
|
-
|
363
|
+
manager = Arel::InsertManager.new
|
364
|
+
manager.into(table)
|
365
|
+
manager.insert(values)
|
366
|
+
execute manager.to_sql, "Fixture Insert"
|
278
367
|
end
|
279
368
|
|
280
|
-
|
281
|
-
|
369
|
+
# Inserts a set of fixtures into the table. Overridden in adapters that require
|
370
|
+
# something beyond a simple insert (eg. Oracle).
|
371
|
+
def insert_fixtures(fixtures, table_name)
|
372
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
373
|
+
`insert_fixtures` is deprecated and will be removed in the next version of Rails.
|
374
|
+
Consider using `insert_fixtures_set` for performance improvement.
|
375
|
+
MSG
|
376
|
+
return if fixtures.empty?
|
377
|
+
|
378
|
+
execute(build_fixture_sql(fixtures, table_name), "Fixtures Insert")
|
282
379
|
end
|
283
380
|
|
284
|
-
def
|
285
|
-
|
381
|
+
def insert_fixtures_set(fixture_set, tables_to_delete = [])
|
382
|
+
fixture_inserts = fixture_set.map do |table_name, fixtures|
|
383
|
+
next if fixtures.empty?
|
384
|
+
|
385
|
+
build_fixture_sql(fixtures, table_name)
|
386
|
+
end.compact
|
387
|
+
|
388
|
+
table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name table}".dup }
|
389
|
+
total_sql = Array.wrap(combine_multi_statements(table_deletes + fixture_inserts))
|
390
|
+
|
391
|
+
disable_referential_integrity do
|
392
|
+
transaction(requires_new: true) do
|
393
|
+
total_sql.each do |sql|
|
394
|
+
execute sql, "Fixtures Load"
|
395
|
+
yield if block_given?
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
286
399
|
end
|
287
400
|
|
288
|
-
def
|
289
|
-
"
|
401
|
+
def empty_insert_statement_value
|
402
|
+
"DEFAULT VALUES"
|
290
403
|
end
|
291
404
|
|
292
405
|
# Sanitizes the given LIMIT parameter in order to prevent SQL injection.
|
293
406
|
#
|
294
407
|
# The +limit+ may be anything that can evaluate to a string via #to_s. It
|
295
|
-
# should look like an integer, or
|
296
|
-
# an Arel SQL literal.
|
408
|
+
# should look like an integer, or an Arel SQL literal.
|
297
409
|
#
|
298
410
|
# Returns Integer and Arel::Nodes::SqlLiteral limits as is.
|
299
|
-
# Returns the sanitized limit parameter, either as an integer, or as a
|
300
|
-
# string which contains a comma-delimited list of integers.
|
301
411
|
def sanitize_limit(limit)
|
302
412
|
if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral)
|
303
413
|
limit
|
304
|
-
elsif limit.to_s =~ /,/
|
305
|
-
Arel.sql limit.to_s.split(',').map{ |i| Integer(i) }.join(',')
|
306
414
|
else
|
307
415
|
Integer(limit)
|
308
416
|
end
|
309
417
|
end
|
310
418
|
|
311
419
|
# The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
|
312
|
-
# on
|
313
|
-
# an UPDATE statement, so in the
|
314
|
-
def join_to_update(update, select)
|
315
|
-
subselect = select
|
316
|
-
subselect.projections = [update.key]
|
420
|
+
# on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
|
421
|
+
# an UPDATE statement, so in the MySQL adapters we redefine this to do that.
|
422
|
+
def join_to_update(update, select, key) # :nodoc:
|
423
|
+
subselect = subquery_for(key, select)
|
317
424
|
|
318
|
-
update.where
|
425
|
+
update.where key.in(subselect)
|
319
426
|
end
|
427
|
+
alias join_to_delete join_to_update
|
428
|
+
|
429
|
+
private
|
430
|
+
def default_insert_value(column)
|
431
|
+
Arel.sql("DEFAULT")
|
432
|
+
end
|
433
|
+
|
434
|
+
def build_fixture_sql(fixtures, table_name)
|
435
|
+
columns = schema_cache.columns_hash(table_name)
|
320
436
|
|
321
|
-
|
322
|
-
|
323
|
-
|
437
|
+
values = fixtures.map do |fixture|
|
438
|
+
fixture = fixture.stringify_keys
|
439
|
+
|
440
|
+
unknown_columns = fixture.keys - columns.keys
|
441
|
+
if unknown_columns.any?
|
442
|
+
raise Fixture::FixtureError, %(table "#{table_name}" has no columns named #{unknown_columns.map(&:inspect).join(', ')}.)
|
443
|
+
end
|
444
|
+
|
445
|
+
columns.map do |name, column|
|
446
|
+
if fixture.key?(name)
|
447
|
+
type = lookup_cast_type_from_column(column)
|
448
|
+
bind = Relation::QueryAttribute.new(name, fixture[name], type)
|
449
|
+
with_yaml_fallback(bind.value_for_database)
|
450
|
+
else
|
451
|
+
default_insert_value(column)
|
452
|
+
end
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
table = Arel::Table.new(table_name)
|
457
|
+
manager = Arel::InsertManager.new
|
458
|
+
manager.into(table)
|
459
|
+
columns.each_key { |column| manager.columns << table[column] }
|
460
|
+
manager.values = manager.create_values_list(values)
|
461
|
+
|
462
|
+
manager.to_sql
|
463
|
+
end
|
464
|
+
|
465
|
+
def combine_multi_statements(total_sql)
|
466
|
+
total_sql.join(";\n")
|
467
|
+
end
|
468
|
+
|
469
|
+
# Returns a subquery for the given key using the join information.
|
470
|
+
def subquery_for(key, select)
|
471
|
+
subselect = select.clone
|
472
|
+
subselect.projections = [key]
|
473
|
+
subselect
|
474
|
+
end
|
475
|
+
|
476
|
+
# Returns an ActiveRecord::Result instance.
|
324
477
|
def select(sql, name = nil, binds = [])
|
478
|
+
exec_query(sql, name, binds, prepare: false)
|
479
|
+
end
|
480
|
+
|
481
|
+
def select_prepared(sql, name = nil, binds = [])
|
482
|
+
exec_query(sql, name, binds, prepare: true)
|
325
483
|
end
|
326
|
-
undef_method :select
|
327
484
|
|
328
|
-
|
329
|
-
|
330
|
-
execute(sql, name)
|
331
|
-
id_value
|
485
|
+
def sql_for_insert(sql, pk, id_value, sequence_name, binds)
|
486
|
+
[sql, binds]
|
332
487
|
end
|
333
488
|
|
334
|
-
|
335
|
-
|
336
|
-
execute(sql, name)
|
489
|
+
def last_inserted_id(result)
|
490
|
+
single_value_from_rows(result.rows)
|
337
491
|
end
|
338
492
|
|
339
|
-
|
340
|
-
|
341
|
-
|
493
|
+
def single_value_from_rows(rows)
|
494
|
+
row = rows.first
|
495
|
+
row && row.first
|
342
496
|
end
|
343
497
|
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
if rollback
|
348
|
-
records = @_current_transaction_records.flatten
|
349
|
-
@_current_transaction_records.clear
|
498
|
+
def arel_from_relation(relation)
|
499
|
+
if relation.is_a?(Relation)
|
500
|
+
relation.arel
|
350
501
|
else
|
351
|
-
|
502
|
+
relation
|
352
503
|
end
|
504
|
+
end
|
353
505
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
506
|
+
# Fixture value is quoted by Arel, however scalar values
|
507
|
+
# are not quotable. In this case we want to convert
|
508
|
+
# the column value to YAML.
|
509
|
+
def with_yaml_fallback(value)
|
510
|
+
if value.is_a?(Hash) || value.is_a?(Array)
|
511
|
+
YAML.dump(value)
|
512
|
+
else
|
513
|
+
value
|
362
514
|
end
|
363
515
|
end
|
364
516
|
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
unless records.blank?
|
370
|
-
records.uniq.each do |record|
|
371
|
-
begin
|
372
|
-
record.committed!
|
373
|
-
rescue Exception => e
|
374
|
-
record.logger.error(e) if record.respond_to?(:logger) && record.logger
|
375
|
-
end
|
376
|
-
end
|
517
|
+
class PartialQueryCollector
|
518
|
+
def initialize
|
519
|
+
@parts = []
|
520
|
+
@binds = []
|
377
521
|
end
|
378
|
-
end
|
379
522
|
|
380
|
-
|
381
|
-
|
382
|
-
|
523
|
+
def <<(str)
|
524
|
+
@parts << str
|
525
|
+
self
|
526
|
+
end
|
383
527
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
528
|
+
def add_bind(obj)
|
529
|
+
@binds << obj
|
530
|
+
@parts << Arel::Nodes::BindParam.new(1)
|
531
|
+
self
|
532
|
+
end
|
533
|
+
|
534
|
+
def value
|
535
|
+
[@parts, @binds]
|
536
|
+
end
|
537
|
+
end
|
388
538
|
end
|
389
539
|
end
|
390
540
|
end
|