activerecord 6.1.3.2 → 7.0.0.alpha2
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 +4 -4
- data/CHANGELOG.md +734 -1058
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +0 -10
- data/lib/active_record/associations/association.rb +35 -7
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +16 -6
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +8 -2
- data/lib/active_record/associations/builder/belongs_to.rb +19 -6
- data/lib/active_record/associations/builder/collection_association.rb +1 -1
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +24 -25
- data/lib/active_record/associations/collection_proxy.rb +8 -3
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/preloader/association.rb +161 -49
- data/lib/active_record/associations/preloader/batch.rb +51 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +37 -11
- data/lib/active_record/associations/preloader.rb +46 -110
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +76 -81
- data/lib/active_record/asynchronous_queries_tracker.rb +57 -0
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +41 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +7 -5
- data/lib/active_record/attribute_methods/serialization.rb +66 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +6 -9
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +3 -18
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/yaml_column.rb +11 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +31 -558
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -7
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -18
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -9
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
- data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
- data/lib/active_record/connection_adapters/abstract_adapter.rb +115 -69
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +6 -2
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -21
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +1 -3
- data/lib/active_record/connection_adapters/pool_manager.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +6 -6
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +157 -100
- data/lib/active_record/connection_adapters/schema_cache.rb +35 -4
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +0 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -17
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
- data/lib/active_record/connection_adapters.rb +8 -5
- data/lib/active_record/connection_handling.rb +20 -38
- data/lib/active_record/core.rb +129 -117
- data/lib/active_record/database_configurations/database_config.rb +12 -0
- data/lib/active_record/database_configurations/hash_config.rb +27 -1
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +18 -9
- data/lib/active_record/delegated_type.rb +33 -11
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +61 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +208 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +29 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +80 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +44 -46
- data/lib/active_record/errors.rb +66 -3
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +40 -5
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +16 -11
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +55 -17
- data/lib/active_record/insert_all.rb +39 -6
- data/lib/active_record/integration.rb +1 -1
- data/lib/active_record/internal_metadata.rb +3 -5
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/log_subscriber.rb +6 -2
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +8 -3
- data/lib/active_record/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +83 -1
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +109 -79
- data/lib/active_record/model_schema.rb +46 -32
- data/lib/active_record/nested_attributes.rb +3 -3
- data/lib/active_record/no_touching.rb +2 -2
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +134 -45
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +203 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +117 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +83 -58
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +45 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +3 -3
- data/lib/active_record/relation/calculations.rb +42 -25
- data/lib/active_record/relation/delegation.rb +6 -6
- data/lib/active_record/relation/finder_methods.rb +32 -23
- data/lib/active_record/relation/merger.rb +20 -13
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +5 -11
- data/lib/active_record/relation/query_methods.rb +233 -50
- data/lib/active_record/relation/record_fetch_warning.rb +2 -2
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +22 -15
- data/lib/active_record/relation.rb +170 -87
- data/lib/active_record/result.rb +17 -2
- data/lib/active_record/runtime_registry.rb +2 -4
- data/lib/active_record/sanitization.rb +11 -7
- data/lib/active_record/schema_dumper.rb +3 -3
- data/lib/active_record/schema_migration.rb +0 -4
- data/lib/active_record/scoping/default.rb +62 -15
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +40 -22
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/tasks/database_tasks.rb +107 -23
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +45 -4
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +9 -14
- data/lib/active_record/translation.rb +2 -2
- data/lib/active_record/type/adapter_specific_registry.rb +32 -7
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +1 -1
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/numericality.rb +1 -1
- data/lib/active_record.rb +170 -2
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/composite.rb +3 -3
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +18 -22
- data/lib/arel/delete_manager.rb +2 -4
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +8 -13
- data/lib/arel/nodes/homogeneous_in.rb +4 -0
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/update_statement.rb +3 -2
- data/lib/arel/predications.rb +3 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +0 -1
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +2 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +6 -1
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +44 -3
- data/lib/arel.rb +1 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- metadata +55 -16
@@ -23,8 +23,12 @@ module ActiveRecord
|
|
23
23
|
@name_to_pool_config[shard]
|
24
24
|
end
|
25
25
|
|
26
|
-
def set_pool_config(
|
27
|
-
|
26
|
+
def set_pool_config(role, shard, pool_config)
|
27
|
+
if pool_config
|
28
|
+
@name_to_pool_config[shard] = pool_config
|
29
|
+
else
|
30
|
+
raise ArgumentError, "The `pool_config` for the :#{role} role and :#{shard} shard was `nil`. Please check your configuration. If you want your writing role to be something other than `:writing` set `config.active_record.writing_role` in your application configuration. The same setting should be applied for the `reading_role` if applicable."
|
31
|
+
end
|
28
32
|
end
|
29
33
|
end
|
30
34
|
end
|
@@ -38,21 +38,16 @@ module ActiveRecord
|
|
38
38
|
end
|
39
39
|
|
40
40
|
# Executes the SQL statement in the context of this connection.
|
41
|
-
def execute(sql, name = nil)
|
42
|
-
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
# make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
|
47
|
-
# made since we established the connection
|
48
|
-
@connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
|
41
|
+
def execute(sql, name = nil, async: false)
|
42
|
+
sql = transform_query(sql)
|
43
|
+
check_if_write_query(sql)
|
49
44
|
|
50
|
-
|
45
|
+
raw_execute(sql, name, async: async)
|
51
46
|
end
|
52
47
|
|
53
|
-
def exec_query(sql, name = "SQL", binds = [], prepare: false)
|
48
|
+
def exec_query(sql, name = "SQL", binds = [], prepare: false, async: false) # :nodoc:
|
54
49
|
if without_prepared_statement?(binds)
|
55
|
-
execute_and_free(sql, name) do |result|
|
50
|
+
execute_and_free(sql, name, async: async) do |result|
|
56
51
|
if result
|
57
52
|
build_result(columns: result.fields, rows: result.to_a)
|
58
53
|
else
|
@@ -60,7 +55,7 @@ module ActiveRecord
|
|
60
55
|
end
|
61
56
|
end
|
62
57
|
else
|
63
|
-
exec_stmt_and_free(sql, name, binds, cache_stmt: prepare) do |_, result|
|
58
|
+
exec_stmt_and_free(sql, name, binds, cache_stmt: prepare, async: async) do |_, result|
|
64
59
|
if result
|
65
60
|
build_result(columns: result.fields, rows: result.to_a)
|
66
61
|
else
|
@@ -70,7 +65,7 @@ module ActiveRecord
|
|
70
65
|
end
|
71
66
|
end
|
72
67
|
|
73
|
-
def exec_delete(sql, name = nil, binds = [])
|
68
|
+
def exec_delete(sql, name = nil, binds = []) # :nodoc:
|
74
69
|
if without_prepared_statement?(binds)
|
75
70
|
@lock.synchronize do
|
76
71
|
execute_and_free(sql, name) { @connection.affected_rows }
|
@@ -81,10 +76,28 @@ module ActiveRecord
|
|
81
76
|
end
|
82
77
|
alias :exec_update :exec_delete
|
83
78
|
|
79
|
+
# https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_current-timestamp
|
80
|
+
# https://dev.mysql.com/doc/refman/5.7/en/date-and-time-type-syntax.html
|
81
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP(6)").freeze # :nodoc:
|
82
|
+
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
83
|
+
|
84
|
+
def high_precision_current_timestamp
|
85
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP
|
86
|
+
end
|
87
|
+
|
84
88
|
private
|
89
|
+
def raw_execute(sql, name, async: false)
|
90
|
+
# make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
91
|
+
# made since we established the connection
|
92
|
+
@connection.query_options[:database_timezone] = ActiveRecord.default_timezone
|
93
|
+
|
94
|
+
super
|
95
|
+
end
|
96
|
+
|
85
97
|
def execute_batch(statements, name = nil)
|
98
|
+
statements = statements.map { |sql| transform_query(sql) }
|
86
99
|
combine_multi_statements(statements).each do |statement|
|
87
|
-
|
100
|
+
raw_execute(statement, name)
|
88
101
|
end
|
89
102
|
@connection.abandon_results!
|
90
103
|
end
|
@@ -148,21 +161,20 @@ module ActiveRecord
|
|
148
161
|
@max_allowed_packet ||= show_variable("max_allowed_packet")
|
149
162
|
end
|
150
163
|
|
151
|
-
def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
|
152
|
-
|
153
|
-
|
154
|
-
end
|
164
|
+
def exec_stmt_and_free(sql, name, binds, cache_stmt: false, async: false)
|
165
|
+
sql = transform_query(sql)
|
166
|
+
check_if_write_query(sql)
|
155
167
|
|
156
168
|
materialize_transactions
|
157
169
|
mark_transaction_written_if_write(sql)
|
158
170
|
|
159
|
-
# make sure we carry over any changes to ActiveRecord
|
171
|
+
# make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
160
172
|
# made since we established the connection
|
161
|
-
@connection.query_options[:database_timezone] = ActiveRecord
|
173
|
+
@connection.query_options[:database_timezone] = ActiveRecord.default_timezone
|
162
174
|
|
163
175
|
type_casted_binds = type_casted_binds(binds)
|
164
176
|
|
165
|
-
log(sql, name, binds, type_casted_binds) do
|
177
|
+
log(sql, name, binds, type_casted_binds, async: async) do
|
166
178
|
if cache_stmt
|
167
179
|
stmt = @statements[sql] ||= @connection.prepare(sql)
|
168
180
|
else
|
@@ -6,6 +6,21 @@ module ActiveRecord
|
|
6
6
|
module ConnectionAdapters
|
7
7
|
module MySQL
|
8
8
|
module Quoting # :nodoc:
|
9
|
+
def quote_bound_value(value)
|
10
|
+
case value
|
11
|
+
when Numeric
|
12
|
+
_quote(value.to_s)
|
13
|
+
when BigDecimal
|
14
|
+
_quote(value.to_s("F"))
|
15
|
+
when true
|
16
|
+
"'1'"
|
17
|
+
when false
|
18
|
+
"'0'"
|
19
|
+
else
|
20
|
+
_quote(value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
9
24
|
def quote_column_name(name)
|
10
25
|
self.class.quoted_column_names[name] ||= "`#{super.gsub('`', '``')}`"
|
11
26
|
end
|
@@ -79,7 +94,7 @@ module ActiveRecord
|
|
79
94
|
# We need to check explicitly for ActiveSupport::TimeWithZone because
|
80
95
|
# we need to transform it to Time objects but we don't want to
|
81
96
|
# transform Time objects to themselves.
|
82
|
-
if ActiveRecord
|
97
|
+
if ActiveRecord.default_timezone == :utc
|
83
98
|
value.getutc
|
84
99
|
else
|
85
100
|
value.getlocal
|
@@ -167,6 +167,9 @@ module ActiveRecord
|
|
167
167
|
elsif type_metadata.extra == "DEFAULT_GENERATED"
|
168
168
|
default = +"(#{default})" unless default.start_with?("(")
|
169
169
|
default, default_function = nil, default
|
170
|
+
elsif type_metadata.type == :text && default
|
171
|
+
# strip and unescape quotes
|
172
|
+
default = default[1...-1].gsub("\\'", "'")
|
170
173
|
end
|
171
174
|
|
172
175
|
MySQL::Column.new(
|
@@ -30,7 +30,11 @@ module ActiveRecord
|
|
30
30
|
|
31
31
|
module ConnectionAdapters
|
32
32
|
class Mysql2Adapter < AbstractMysqlAdapter
|
33
|
-
ER_BAD_DB_ERROR
|
33
|
+
ER_BAD_DB_ERROR = 1049
|
34
|
+
ER_ACCESS_DENIED_ERROR = 1045
|
35
|
+
ER_CONN_HOST_ERROR = 2003
|
36
|
+
ER_UNKNOWN_HOST_ERROR = 2005
|
37
|
+
|
34
38
|
ADAPTER_NAME = "Mysql2"
|
35
39
|
|
36
40
|
include MySQL::DatabaseStatements
|
@@ -40,7 +44,11 @@ module ActiveRecord
|
|
40
44
|
Mysql2::Client.new(config)
|
41
45
|
rescue Mysql2::Error => error
|
42
46
|
if error.error_number == ConnectionAdapters::Mysql2Adapter::ER_BAD_DB_ERROR
|
43
|
-
raise ActiveRecord::NoDatabaseError
|
47
|
+
raise ActiveRecord::NoDatabaseError.db_error(config[:database])
|
48
|
+
elsif error.error_number == ConnectionAdapters::Mysql2Adapter::ER_ACCESS_DENIED_ERROR
|
49
|
+
raise ActiveRecord::DatabaseConnectionError.username_error(config[:username])
|
50
|
+
elsif [ConnectionAdapters::Mysql2Adapter::ER_CONN_HOST_ERROR, ConnectionAdapters::Mysql2Adapter::ER_UNKNOWN_HOST_ERROR].include?(error.error_number)
|
51
|
+
raise ActiveRecord::DatabaseConnectionError.hostname_error(config[:host])
|
44
52
|
else
|
45
53
|
raise ActiveRecord::ConnectionNotEstablished, error.message
|
46
54
|
end
|
@@ -81,11 +89,9 @@ module ActiveRecord
|
|
81
89
|
|
82
90
|
# HELPER METHODS ===========================================
|
83
91
|
|
84
|
-
def each_hash(result) # :nodoc:
|
92
|
+
def each_hash(result, &block) # :nodoc:
|
85
93
|
if block_given?
|
86
|
-
result.each(as: :hash, symbolize_keys: true)
|
87
|
-
yield row
|
88
|
-
end
|
94
|
+
result.each(as: :hash, symbolize_keys: true, &block)
|
89
95
|
else
|
90
96
|
to_enum(:each_hash, result)
|
91
97
|
end
|
@@ -26,9 +26,7 @@ module ActiveRecord
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def connection_specification_name
|
29
|
-
if connection_klass.
|
30
|
-
connection_klass
|
31
|
-
elsif connection_klass.primary_class?
|
29
|
+
if connection_klass.primary_class?
|
32
30
|
"ActiveRecord::Base"
|
33
31
|
else
|
34
32
|
connection_klass.name
|
@@ -36,7 +36,11 @@ module ActiveRecord
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def set_pool_config(role, shard, pool_config)
|
39
|
-
|
39
|
+
if pool_config
|
40
|
+
@name_to_role_mapping[role][shard] = pool_config
|
41
|
+
else
|
42
|
+
raise ArgumentError, "The `pool_config` for the :#{role} role and :#{shard} shard was `nil`. Please check your configuration. If you want your writing role to be something other than `:writing` set `config.active_record.writing_role` in your application configuration. The same setting should be applied for the `reading_role` if applicable."
|
43
|
+
end
|
40
44
|
end
|
41
45
|
end
|
42
46
|
end
|
@@ -10,7 +10,7 @@ module ActiveRecord
|
|
10
10
|
end
|
11
11
|
|
12
12
|
# Queries the database and returns the results in an Array-like object
|
13
|
-
def query(sql, name = nil)
|
13
|
+
def query(sql, name = nil) # :nodoc:
|
14
14
|
materialize_transactions
|
15
15
|
mark_transaction_written_if_write(sql)
|
16
16
|
|
@@ -35,9 +35,8 @@ module ActiveRecord
|
|
35
35
|
# Note: the PG::Result object is manually memory managed; if you don't
|
36
36
|
# need it specifically, you may want consider the <tt>exec_query</tt> wrapper.
|
37
37
|
def execute(sql, name = nil)
|
38
|
-
|
39
|
-
|
40
|
-
end
|
38
|
+
sql = transform_query(sql)
|
39
|
+
check_if_write_query(sql)
|
41
40
|
|
42
41
|
materialize_transactions
|
43
42
|
mark_transaction_written_if_write(sql)
|
@@ -49,8 +48,8 @@ module ActiveRecord
|
|
49
48
|
end
|
50
49
|
end
|
51
50
|
|
52
|
-
def exec_query(sql, name = "SQL", binds = [], prepare: false)
|
53
|
-
execute_and_clear(sql, name, binds, prepare: prepare) do |result|
|
51
|
+
def exec_query(sql, name = "SQL", binds = [], prepare: false, async: false) # :nodoc:
|
52
|
+
execute_and_clear(sql, name, binds, prepare: prepare, async: async) do |result|
|
54
53
|
types = {}
|
55
54
|
fields = result.fields
|
56
55
|
fields.each_with_index do |fname, i|
|
@@ -66,7 +65,7 @@ module ActiveRecord
|
|
66
65
|
end
|
67
66
|
end
|
68
67
|
|
69
|
-
def exec_delete(sql, name = nil, binds = [])
|
68
|
+
def exec_delete(sql, name = nil, binds = []) # :nodoc:
|
70
69
|
execute_and_clear(sql, name, binds) { |result| result.cmd_tuples }
|
71
70
|
end
|
72
71
|
alias :exec_update :exec_delete
|
@@ -86,7 +85,7 @@ module ActiveRecord
|
|
86
85
|
end
|
87
86
|
private :sql_for_insert
|
88
87
|
|
89
|
-
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
88
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil) # :nodoc:
|
90
89
|
if use_insert_returning? || pk == false
|
91
90
|
super
|
92
91
|
else
|
@@ -105,25 +104,33 @@ module ActiveRecord
|
|
105
104
|
end
|
106
105
|
|
107
106
|
# Begins a transaction.
|
108
|
-
def begin_db_transaction
|
107
|
+
def begin_db_transaction # :nodoc:
|
109
108
|
execute("BEGIN", "TRANSACTION")
|
110
109
|
end
|
111
110
|
|
112
|
-
def begin_isolated_db_transaction(isolation)
|
111
|
+
def begin_isolated_db_transaction(isolation) # :nodoc:
|
113
112
|
begin_db_transaction
|
114
113
|
execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
|
115
114
|
end
|
116
115
|
|
117
116
|
# Commits a transaction.
|
118
|
-
def commit_db_transaction
|
117
|
+
def commit_db_transaction # :nodoc:
|
119
118
|
execute("COMMIT", "TRANSACTION")
|
120
119
|
end
|
121
120
|
|
122
121
|
# Aborts a transaction.
|
123
|
-
def exec_rollback_db_transaction
|
122
|
+
def exec_rollback_db_transaction # :nodoc:
|
124
123
|
execute("ROLLBACK", "TRANSACTION")
|
125
124
|
end
|
126
125
|
|
126
|
+
# From https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT
|
127
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP").freeze # :nodoc:
|
128
|
+
private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
|
129
|
+
|
130
|
+
def high_precision_current_timestamp
|
131
|
+
HIGH_PRECISION_CURRENT_TIMESTAMP
|
132
|
+
end
|
133
|
+
|
127
134
|
private
|
128
135
|
def execute_batch(statements, name = nil)
|
129
136
|
execute(combine_multi_statements(statements))
|
@@ -16,6 +16,14 @@ module ActiveRecord
|
|
16
16
|
super
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
def type_cast_for_schema(value)
|
21
|
+
case value
|
22
|
+
when ::Float::INFINITY then "::Float::INFINITY"
|
23
|
+
when -::Float::INFINITY then "-::Float::INFINITY"
|
24
|
+
else super
|
25
|
+
end
|
26
|
+
end
|
19
27
|
end
|
20
28
|
end
|
21
29
|
end
|
@@ -1,10 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "strscan"
|
4
|
+
|
3
5
|
module ActiveRecord
|
4
6
|
module ConnectionAdapters
|
5
7
|
module PostgreSQL
|
6
8
|
module OID # :nodoc:
|
7
9
|
class Hstore < Type::Value # :nodoc:
|
10
|
+
ERROR = "Invalid Hstore document: %s"
|
11
|
+
|
8
12
|
include ActiveModel::Type::Helpers::Mutable
|
9
13
|
|
10
14
|
def type
|
@@ -12,15 +16,56 @@ module ActiveRecord
|
|
12
16
|
end
|
13
17
|
|
14
18
|
def deserialize(value)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
return value unless value.is_a?(::String)
|
20
|
+
|
21
|
+
scanner = StringScanner.new(value)
|
22
|
+
hash = {}
|
23
|
+
|
24
|
+
until scanner.eos?
|
25
|
+
unless scanner.skip(/"/)
|
26
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
27
|
+
end
|
28
|
+
|
29
|
+
unless key = scanner.scan_until(/(?<!\\)(?=")/)
|
30
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
31
|
+
end
|
32
|
+
|
33
|
+
unless scanner.skip(/"=>?/)
|
34
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
35
|
+
end
|
36
|
+
|
37
|
+
if scanner.scan(/NULL/)
|
38
|
+
value = nil
|
39
|
+
else
|
40
|
+
unless scanner.skip(/"/)
|
41
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
42
|
+
end
|
43
|
+
|
44
|
+
unless value = scanner.scan_until(/(?<!\\)(?=")/)
|
45
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
46
|
+
end
|
47
|
+
|
48
|
+
unless scanner.skip(/"/)
|
49
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
key.gsub!('\"', '"')
|
54
|
+
key.gsub!("\\\\", "\\")
|
55
|
+
|
56
|
+
if value
|
57
|
+
value.gsub!('\"', '"')
|
58
|
+
value.gsub!("\\\\", "\\")
|
59
|
+
end
|
60
|
+
|
61
|
+
hash[key] = value
|
62
|
+
|
63
|
+
unless scanner.skip(/, /) || scanner.eos?
|
64
|
+
raise(ArgumentError, ERROR % scanner.string.inspect)
|
65
|
+
end
|
23
66
|
end
|
67
|
+
|
68
|
+
hash
|
24
69
|
end
|
25
70
|
|
26
71
|
def serialize(value)
|
@@ -46,12 +91,6 @@ module ActiveRecord
|
|
46
91
|
end
|
47
92
|
|
48
93
|
private
|
49
|
-
HstorePair = begin
|
50
|
-
quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
|
51
|
-
unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
|
52
|
-
/(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
|
53
|
-
end
|
54
|
-
|
55
94
|
def escape_hstore(value)
|
56
95
|
if value.nil?
|
57
96
|
"NULL"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module PostgreSQL
|
6
|
+
module OID # :nodoc:
|
7
|
+
class Timestamp < DateTime # :nodoc:
|
8
|
+
def type
|
9
|
+
real_type_unless_aliased(:timestamp)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|