activerecord 7.2.3 → 8.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +192 -1261
- data/README.rdoc +2 -2
- data/lib/active_record/associations/alias_tracker.rb +4 -6
- data/lib/active_record/associations/association.rb +25 -5
- data/lib/active_record/associations/belongs_to_association.rb +2 -18
- data/lib/active_record/associations/builder/association.rb +7 -6
- data/lib/active_record/associations/collection_association.rb +4 -4
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +4 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
- data/lib/active_record/associations/preloader/association.rb +2 -2
- data/lib/active_record/associations/singular_association.rb +8 -3
- data/lib/active_record/associations.rb +50 -32
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods.rb +19 -24
- data/lib/active_record/attributes.rb +26 -37
- data/lib/active_record/autosave_association.rb +81 -49
- data/lib/active_record/base.rb +2 -2
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +16 -10
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +31 -75
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +90 -43
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +14 -19
- data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +2 -6
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +27 -9
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
- data/lib/active_record/connection_adapters/abstract_adapter.rb +27 -57
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +28 -58
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -15
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -45
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +42 -98
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +2 -16
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -42
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +12 -14
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +51 -9
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +44 -101
- data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +76 -100
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -13
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +8 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +60 -22
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -18
- data/lib/active_record/connection_handling.rb +29 -11
- data/lib/active_record/core.rb +15 -60
- data/lib/active_record/counter_cache.rb +1 -1
- data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -3
- data/lib/active_record/delegated_type.rb +18 -18
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +5 -5
- data/lib/active_record/encryption/encrypted_attribute_type.rb +11 -2
- data/lib/active_record/encryption/encryptor.rb +35 -29
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/scheme.rb +8 -1
- data/lib/active_record/enum.rb +12 -13
- data/lib/active_record/errors.rb +16 -8
- data/lib/active_record/fixture_set/table_row.rb +2 -19
- data/lib/active_record/fixtures.rb +0 -1
- data/lib/active_record/future_result.rb +14 -10
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/insert_all.rb +1 -1
- data/lib/active_record/marshalling.rb +1 -4
- data/lib/active_record/migration/command_recorder.rb +22 -5
- data/lib/active_record/migration/compatibility.rb +5 -2
- data/lib/active_record/migration.rb +36 -35
- data/lib/active_record/model_schema.rb +1 -1
- data/lib/active_record/nested_attributes.rb +4 -6
- data/lib/active_record/persistence.rb +128 -130
- data/lib/active_record/query_cache.rb +5 -4
- data/lib/active_record/query_logs.rb +98 -44
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +10 -10
- data/lib/active_record/railtie.rb +5 -6
- data/lib/active_record/railties/databases.rake +1 -2
- data/lib/active_record/reflection.rb +9 -7
- data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
- data/lib/active_record/relation/batches.rb +132 -72
- data/lib/active_record/relation/calculations.rb +55 -55
- data/lib/active_record/relation/delegation.rb +25 -14
- data/lib/active_record/relation/finder_methods.rb +31 -32
- data/lib/active_record/relation/merger.rb +8 -8
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +0 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +5 -0
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +90 -91
- data/lib/active_record/relation/record_fetch_warning.rb +2 -2
- data/lib/active_record/relation/spawn_methods.rb +1 -1
- data/lib/active_record/relation/where_clause.rb +2 -8
- data/lib/active_record/relation.rb +77 -76
- data/lib/active_record/result.rb +68 -7
- data/lib/active_record/sanitization.rb +7 -6
- data/lib/active_record/schema_dumper.rb +16 -29
- data/lib/active_record/schema_migration.rb +2 -1
- data/lib/active_record/scoping/named.rb +5 -2
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +6 -7
- data/lib/active_record/statement_cache.rb +12 -12
- data/lib/active_record/store.rb +7 -3
- data/lib/active_record/tasks/database_tasks.rb +24 -15
- data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
- data/lib/active_record/tasks/postgresql_database_tasks.rb +0 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
- data/lib/active_record/test_fixtures.rb +12 -0
- data/lib/active_record/testing/query_assertions.rb +2 -2
- data/lib/active_record/token_for.rb +1 -1
- data/lib/active_record/transactions.rb +1 -3
- data/lib/active_record/validations/uniqueness.rb +8 -8
- data/lib/active_record.rb +16 -1
- data/lib/arel/collectors/bind.rb +1 -1
- data/lib/arel/crud.rb +0 -2
- data/lib/arel/delete_manager.rb +0 -5
- data/lib/arel/nodes/delete_statement.rb +2 -4
- data/lib/arel/nodes/update_statement.rb +2 -4
- data/lib/arel/select_manager.rb +2 -6
- data/lib/arel/update_manager.rb +0 -5
- data/lib/arel/visitors/dot.rb +0 -2
- data/lib/arel/visitors/sqlite.rb +0 -25
- data/lib/arel/visitors/to_sql.rb +1 -3
- metadata +14 -11
|
@@ -13,49 +13,10 @@ module ActiveRecord
|
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false) # :nodoc:
|
|
17
|
-
if without_prepared_statement?(binds)
|
|
18
|
-
execute_and_free(sql, name, async: async, allow_retry: allow_retry) do |result|
|
|
19
|
-
if result
|
|
20
|
-
build_result(columns: result.fields, rows: result.to_a)
|
|
21
|
-
else
|
|
22
|
-
build_result(columns: [], rows: [])
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
else
|
|
26
|
-
exec_stmt_and_free(sql, name, binds, cache_stmt: prepare, async: async, allow_retry: allow_retry) do |_, result|
|
|
27
|
-
if result
|
|
28
|
-
build_result(columns: result.fields, rows: result.to_a)
|
|
29
|
-
else
|
|
30
|
-
build_result(columns: [], rows: [])
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def exec_delete(sql, name = nil, binds = []) # :nodoc:
|
|
37
|
-
if without_prepared_statement?(binds)
|
|
38
|
-
with_raw_connection do |conn|
|
|
39
|
-
@affected_rows_before_warnings = nil
|
|
40
|
-
execute_and_free(sql, name) { @affected_rows_before_warnings || conn.affected_rows }
|
|
41
|
-
end
|
|
42
|
-
else
|
|
43
|
-
exec_stmt_and_free(sql, name, binds) { |stmt| stmt.affected_rows }
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
alias :exec_update :exec_delete
|
|
47
|
-
|
|
48
16
|
private
|
|
49
|
-
def
|
|
50
|
-
raw_connection.query_options[:database_timezone] = default_timezone
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def execute_batch(statements, name = nil)
|
|
54
|
-
statements = statements.map { |sql| transform_query(sql) }
|
|
17
|
+
def execute_batch(statements, name = nil, **kwargs)
|
|
55
18
|
combine_multi_statements(statements).each do |statement|
|
|
56
|
-
|
|
57
|
-
raw_execute(statement, name)
|
|
58
|
-
end
|
|
19
|
+
raw_execute(statement, name, batch: true, **kwargs)
|
|
59
20
|
end
|
|
60
21
|
end
|
|
61
22
|
|
|
@@ -77,75 +38,58 @@ module ActiveRecord
|
|
|
77
38
|
end
|
|
78
39
|
end
|
|
79
40
|
|
|
80
|
-
def
|
|
81
|
-
if multi_statements_enabled?
|
|
82
|
-
|
|
41
|
+
def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch: false)
|
|
42
|
+
reset_multi_statement = if batch && !multi_statements_enabled?
|
|
43
|
+
raw_connection.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_ON)
|
|
44
|
+
true
|
|
83
45
|
end
|
|
84
46
|
|
|
85
|
-
|
|
86
|
-
|
|
47
|
+
# Make sure we carry over any changes to ActiveRecord.default_timezone that have been
|
|
48
|
+
# made since we established the connection
|
|
49
|
+
raw_connection.query_options[:database_timezone] = default_timezone
|
|
87
50
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
conn.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
|
|
91
|
-
end
|
|
92
|
-
end
|
|
51
|
+
result = if prepare
|
|
52
|
+
stmt = @statements[sql] ||= raw_connection.prepare(sql)
|
|
93
53
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
notification_payload[:row_count] = result&.size || 0
|
|
103
|
-
result
|
|
54
|
+
begin
|
|
55
|
+
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
|
56
|
+
stmt.execute(*type_casted_binds)
|
|
57
|
+
end
|
|
58
|
+
rescue ::Mysql2::Error
|
|
59
|
+
@statements.delete(sql)
|
|
60
|
+
stmt.close
|
|
61
|
+
raise
|
|
104
62
|
end
|
|
63
|
+
verified!
|
|
64
|
+
else
|
|
65
|
+
raw_connection.query(sql)
|
|
105
66
|
end
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def exec_stmt_and_free(sql, name, binds, cache_stmt: false, async: false, allow_retry: false)
|
|
109
|
-
sql = transform_query(sql)
|
|
110
|
-
check_if_write_query(sql)
|
|
111
67
|
|
|
112
|
-
|
|
68
|
+
notification_payload[:row_count] = result&.size || 0
|
|
113
69
|
|
|
114
|
-
|
|
70
|
+
@affected_rows_before_warnings = raw_connection.affected_rows
|
|
71
|
+
raw_connection.abandon_results!
|
|
115
72
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
begin
|
|
127
|
-
result = ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
|
128
|
-
stmt.execute(*type_casted_binds)
|
|
129
|
-
end
|
|
130
|
-
verified!
|
|
131
|
-
result
|
|
132
|
-
rescue ::Mysql2::Error => e
|
|
133
|
-
if cache_stmt
|
|
134
|
-
@statements.delete(sql)
|
|
135
|
-
else
|
|
136
|
-
stmt.close
|
|
137
|
-
end
|
|
138
|
-
raise e
|
|
139
|
-
end
|
|
73
|
+
verified!
|
|
74
|
+
handle_warnings(sql)
|
|
75
|
+
result
|
|
76
|
+
ensure
|
|
77
|
+
if reset_multi_statement && active?
|
|
78
|
+
raw_connection.set_server_option(::Mysql2::Client::OPTION_MULTI_STATEMENTS_OFF)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
140
81
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
end
|
|
82
|
+
def cast_result(result)
|
|
83
|
+
if result.nil? || result.fields.empty?
|
|
84
|
+
ActiveRecord::Result.empty
|
|
85
|
+
else
|
|
86
|
+
ActiveRecord::Result.new(result.fields, result.to_a)
|
|
147
87
|
end
|
|
148
88
|
end
|
|
89
|
+
|
|
90
|
+
def affected_rows(result)
|
|
91
|
+
@affected_rows_before_warnings
|
|
92
|
+
end
|
|
149
93
|
end
|
|
150
94
|
end
|
|
151
95
|
end
|
|
@@ -55,6 +55,7 @@ module ActiveRecord
|
|
|
55
55
|
def initialize(...)
|
|
56
56
|
super
|
|
57
57
|
|
|
58
|
+
@affected_rows_before_warnings = nil
|
|
58
59
|
@config[:flags] ||= 0
|
|
59
60
|
|
|
60
61
|
if @config[:flags].kind_of? Array
|
|
@@ -92,14 +93,6 @@ module ActiveRecord
|
|
|
92
93
|
|
|
93
94
|
# HELPER METHODS ===========================================
|
|
94
95
|
|
|
95
|
-
def each_hash(result, &block) # :nodoc:
|
|
96
|
-
if block_given?
|
|
97
|
-
result.each(as: :hash, symbolize_keys: true, &block)
|
|
98
|
-
else
|
|
99
|
-
to_enum(:each_hash, result)
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
96
|
def error_number(exception)
|
|
104
97
|
exception.error_number if exception.respond_to?(:error_number)
|
|
105
98
|
end
|
|
@@ -113,14 +106,7 @@ module ActiveRecord
|
|
|
113
106
|
end
|
|
114
107
|
|
|
115
108
|
def active?
|
|
116
|
-
|
|
117
|
-
@lock.synchronize do
|
|
118
|
-
if @raw_connection&.ping
|
|
119
|
-
verified!
|
|
120
|
-
true
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
end || false
|
|
109
|
+
connected? && @lock.synchronize { @raw_connection&.ping } || false
|
|
124
110
|
end
|
|
125
111
|
|
|
126
112
|
alias :reset! :reconnect!
|
|
@@ -12,16 +12,8 @@ module ActiveRecord
|
|
|
12
12
|
|
|
13
13
|
# Queries the database and returns the results in an Array-like object
|
|
14
14
|
def query(sql, name = nil) # :nodoc:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
log(sql, name) do |notification_payload|
|
|
18
|
-
with_raw_connection do |conn|
|
|
19
|
-
result = conn.async_exec(sql).map_types!(@type_map_for_results).values
|
|
20
|
-
verified!
|
|
21
|
-
notification_payload[:row_count] = result.count
|
|
22
|
-
result
|
|
23
|
-
end
|
|
24
|
-
end
|
|
15
|
+
result = internal_execute(sql, name)
|
|
16
|
+
result.map_types!(@type_map_for_results).values
|
|
25
17
|
end
|
|
26
18
|
|
|
27
19
|
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
|
@@ -50,36 +42,6 @@ module ActiveRecord
|
|
|
50
42
|
@notice_receiver_sql_warnings = []
|
|
51
43
|
end
|
|
52
44
|
|
|
53
|
-
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
|
|
54
|
-
log(sql, name, async: async) do |notification_payload|
|
|
55
|
-
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
|
56
|
-
result = conn.async_exec(sql)
|
|
57
|
-
verified!
|
|
58
|
-
handle_warnings(result)
|
|
59
|
-
notification_payload[:row_count] = result.count
|
|
60
|
-
result
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def internal_exec_query(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: true) # :nodoc:
|
|
66
|
-
execute_and_clear(sql, name, binds, prepare: prepare, async: async, allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |result|
|
|
67
|
-
types = {}
|
|
68
|
-
fields = result.fields
|
|
69
|
-
fields.each_with_index do |fname, i|
|
|
70
|
-
ftype = result.ftype i
|
|
71
|
-
fmod = result.fmod i
|
|
72
|
-
types[fname] = types[i] = get_oid_type(ftype, fmod, fname)
|
|
73
|
-
end
|
|
74
|
-
build_result(columns: fields, rows: result.values, column_types: types.freeze)
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def exec_delete(sql, name = nil, binds = []) # :nodoc:
|
|
79
|
-
execute_and_clear(sql, name, binds) { |result| result.cmd_tuples }
|
|
80
|
-
end
|
|
81
|
-
alias :exec_update :exec_delete
|
|
82
|
-
|
|
83
45
|
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil) # :nodoc:
|
|
84
46
|
if use_insert_returning? || pk == false
|
|
85
47
|
super
|
|
@@ -170,8 +132,68 @@ module ActiveRecord
|
|
|
170
132
|
rescue PG::Error
|
|
171
133
|
end
|
|
172
134
|
|
|
173
|
-
def
|
|
174
|
-
|
|
135
|
+
def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch: false)
|
|
136
|
+
update_typemap_for_default_timezone
|
|
137
|
+
result = if prepare
|
|
138
|
+
begin
|
|
139
|
+
stmt_key = prepare_statement(sql, binds, raw_connection)
|
|
140
|
+
notification_payload[:statement_name] = stmt_key
|
|
141
|
+
raw_connection.exec_prepared(stmt_key, type_casted_binds)
|
|
142
|
+
rescue PG::FeatureNotSupported => error
|
|
143
|
+
if is_cached_plan_failure?(error)
|
|
144
|
+
# Nothing we can do if we are in a transaction because all commands
|
|
145
|
+
# will raise InFailedSQLTransaction
|
|
146
|
+
if in_transaction?
|
|
147
|
+
raise PreparedStatementCacheExpired.new(error.message, connection_pool: @pool)
|
|
148
|
+
else
|
|
149
|
+
@lock.synchronize do
|
|
150
|
+
# outside of transactions we can simply flush this query and retry
|
|
151
|
+
@statements.delete sql_key(sql)
|
|
152
|
+
end
|
|
153
|
+
retry
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
raise
|
|
158
|
+
end
|
|
159
|
+
elsif binds.nil? || binds.empty?
|
|
160
|
+
raw_connection.async_exec(sql)
|
|
161
|
+
else
|
|
162
|
+
raw_connection.exec_params(sql, type_casted_binds)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
verified!
|
|
166
|
+
handle_warnings(result)
|
|
167
|
+
notification_payload[:row_count] = result.count
|
|
168
|
+
result
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def cast_result(result)
|
|
172
|
+
if result.fields.empty?
|
|
173
|
+
result.clear
|
|
174
|
+
return ActiveRecord::Result.empty
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
types = {}
|
|
178
|
+
fields = result.fields
|
|
179
|
+
fields.each_with_index do |fname, i|
|
|
180
|
+
ftype = result.ftype i
|
|
181
|
+
fmod = result.fmod i
|
|
182
|
+
types[fname] = types[i] = get_oid_type(ftype, fmod, fname)
|
|
183
|
+
end
|
|
184
|
+
ar_result = ActiveRecord::Result.new(fields, result.values, types.freeze)
|
|
185
|
+
result.clear
|
|
186
|
+
ar_result
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def affected_rows(result)
|
|
190
|
+
affected_rows = result.cmd_tuples
|
|
191
|
+
result.clear
|
|
192
|
+
affected_rows
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def execute_batch(statements, name = nil, **kwargs)
|
|
196
|
+
raw_execute(combine_multi_statements(statements), name, batch: true, **kwargs)
|
|
175
197
|
end
|
|
176
198
|
|
|
177
199
|
def build_truncate_statements(table_names)
|
|
@@ -25,6 +25,10 @@ module ActiveRecord
|
|
|
25
25
|
build_point(x, y)
|
|
26
26
|
when ::Array
|
|
27
27
|
build_point(*value)
|
|
28
|
+
when ::Hash
|
|
29
|
+
return if value.blank?
|
|
30
|
+
|
|
31
|
+
build_point(*values_array_from_hash(value))
|
|
28
32
|
else
|
|
29
33
|
value
|
|
30
34
|
end
|
|
@@ -36,6 +40,8 @@ module ActiveRecord
|
|
|
36
40
|
"(#{number_for_point(value.x)},#{number_for_point(value.y)})"
|
|
37
41
|
when ::Array
|
|
38
42
|
serialize(build_point(*value))
|
|
43
|
+
when ::Hash
|
|
44
|
+
serialize(build_point(*values_array_from_hash(value)))
|
|
39
45
|
else
|
|
40
46
|
super
|
|
41
47
|
end
|
|
@@ -57,6 +63,10 @@ module ActiveRecord
|
|
|
57
63
|
def build_point(x, y)
|
|
58
64
|
ActiveRecord::Point.new(Float(x), Float(y))
|
|
59
65
|
end
|
|
66
|
+
|
|
67
|
+
def values_array_from_hash(value)
|
|
68
|
+
[value.values_at(:x, "x").compact.first, value.values_at(:y, "y").compact.first]
|
|
69
|
+
end
|
|
60
70
|
end
|
|
61
71
|
end
|
|
62
72
|
end
|
|
@@ -229,8 +229,6 @@ module ActiveRecord
|
|
|
229
229
|
end
|
|
230
230
|
|
|
231
231
|
def defined_for?(name: nil, column: nil, **options)
|
|
232
|
-
options = options.slice(*self.options.keys)
|
|
233
|
-
|
|
234
232
|
(name.nil? || self.name == name.to_s) &&
|
|
235
233
|
(column.nil? || Array(self.column) == Array(column).map(&:to_s)) &&
|
|
236
234
|
options.all? { |k, v| self.options[k].to_s == v.to_s }
|
|
@@ -304,8 +302,8 @@ module ActiveRecord
|
|
|
304
302
|
# t.exclusion_constraint("price WITH =, availability_range WITH &&", using: :gist, name: "price_check")
|
|
305
303
|
#
|
|
306
304
|
# See {connection.add_exclusion_constraint}[rdoc-ref:SchemaStatements#add_exclusion_constraint]
|
|
307
|
-
def exclusion_constraint(
|
|
308
|
-
@base.add_exclusion_constraint(name,
|
|
305
|
+
def exclusion_constraint(*args)
|
|
306
|
+
@base.add_exclusion_constraint(name, *args)
|
|
309
307
|
end
|
|
310
308
|
|
|
311
309
|
# Removes the given exclusion constraint from the table.
|
|
@@ -313,8 +311,8 @@ module ActiveRecord
|
|
|
313
311
|
# t.remove_exclusion_constraint(name: "price_check")
|
|
314
312
|
#
|
|
315
313
|
# See {connection.remove_exclusion_constraint}[rdoc-ref:SchemaStatements#remove_exclusion_constraint]
|
|
316
|
-
def remove_exclusion_constraint(
|
|
317
|
-
@base.remove_exclusion_constraint(name,
|
|
314
|
+
def remove_exclusion_constraint(*args)
|
|
315
|
+
@base.remove_exclusion_constraint(name, *args)
|
|
318
316
|
end
|
|
319
317
|
|
|
320
318
|
# Adds a unique constraint.
|
|
@@ -322,8 +320,8 @@ module ActiveRecord
|
|
|
322
320
|
# t.unique_constraint(:position, name: 'unique_position', deferrable: :deferred)
|
|
323
321
|
#
|
|
324
322
|
# See {connection.add_unique_constraint}[rdoc-ref:SchemaStatements#add_unique_constraint]
|
|
325
|
-
def unique_constraint(
|
|
326
|
-
@base.add_unique_constraint(name,
|
|
323
|
+
def unique_constraint(*args)
|
|
324
|
+
@base.add_unique_constraint(name, *args)
|
|
327
325
|
end
|
|
328
326
|
|
|
329
327
|
# Removes the given unique constraint from the table.
|
|
@@ -331,8 +329,8 @@ module ActiveRecord
|
|
|
331
329
|
# t.remove_unique_constraint(name: "unique_position")
|
|
332
330
|
#
|
|
333
331
|
# See {connection.remove_unique_constraint}[rdoc-ref:SchemaStatements#remove_unique_constraint]
|
|
334
|
-
def remove_unique_constraint(
|
|
335
|
-
@base.remove_unique_constraint(name,
|
|
332
|
+
def remove_unique_constraint(*args)
|
|
333
|
+
@base.remove_unique_constraint(name, *args)
|
|
336
334
|
end
|
|
337
335
|
|
|
338
336
|
# Validates the given constraint on the table.
|
|
@@ -341,8 +339,8 @@ module ActiveRecord
|
|
|
341
339
|
# t.validate_constraint "price_check"
|
|
342
340
|
#
|
|
343
341
|
# See {connection.validate_constraint}[rdoc-ref:SchemaStatements#validate_constraint]
|
|
344
|
-
def validate_constraint(
|
|
345
|
-
@base.validate_constraint(name,
|
|
342
|
+
def validate_constraint(*args)
|
|
343
|
+
@base.validate_constraint(name, *args)
|
|
346
344
|
end
|
|
347
345
|
|
|
348
346
|
# Validates the given check constraint on the table
|
|
@@ -351,8 +349,8 @@ module ActiveRecord
|
|
|
351
349
|
# t.validate_check_constraint name: "price_check"
|
|
352
350
|
#
|
|
353
351
|
# See {connection.validate_check_constraint}[rdoc-ref:SchemaStatements#validate_check_constraint]
|
|
354
|
-
def validate_check_constraint(
|
|
355
|
-
@base.validate_check_constraint(name,
|
|
352
|
+
def validate_check_constraint(*args)
|
|
353
|
+
@base.validate_check_constraint(name, *args)
|
|
356
354
|
end
|
|
357
355
|
end
|
|
358
356
|
|
|
@@ -22,7 +22,7 @@ module ActiveRecord
|
|
|
22
22
|
stream.puts " # Custom types defined in this database."
|
|
23
23
|
stream.puts " # Note that some types may not work with other database engines. Be careful if changing database."
|
|
24
24
|
types.sort.each do |name, values|
|
|
25
|
-
stream.puts " create_enum #{name.inspect}, #{values.inspect}"
|
|
25
|
+
stream.puts " create_enum #{name.inspect}, #{values.split(",").inspect}"
|
|
26
26
|
end
|
|
27
27
|
stream.puts
|
|
28
28
|
end
|
|
@@ -54,9 +54,9 @@ module ActiveRecord
|
|
|
54
54
|
execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
-
def drop_table(
|
|
58
|
-
schema_cache.clear_data_source_cache!(table_name.to_s)
|
|
59
|
-
execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
|
|
57
|
+
def drop_table(*table_names, **options) # :nodoc:
|
|
58
|
+
table_names.each { |table_name| schema_cache.clear_data_source_cache!(table_name.to_s) }
|
|
59
|
+
execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{table_names.map { |table_name| quote_table_name(table_name) }.join(', ')}#{' CASCADE' if options[:force] == :cascade}"
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
# Returns true if schema exists.
|
|
@@ -152,9 +152,23 @@ module ActiveRecord
|
|
|
152
152
|
end
|
|
153
153
|
|
|
154
154
|
def table_options(table_name) # :nodoc:
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
options = {}
|
|
156
|
+
|
|
157
|
+
comment = table_comment(table_name)
|
|
158
|
+
|
|
159
|
+
options[:comment] = comment if comment
|
|
160
|
+
|
|
161
|
+
inherited_table_names = inherited_table_names(table_name).presence
|
|
162
|
+
|
|
163
|
+
options[:options] = "INHERITS (#{inherited_table_names.join(", ")})" if inherited_table_names
|
|
164
|
+
|
|
165
|
+
if !options[:options] && supports_native_partitioning?
|
|
166
|
+
partition_definition = table_partition_definition(table_name)
|
|
167
|
+
|
|
168
|
+
options[:options] = "PARTITION BY #{partition_definition}" if partition_definition
|
|
157
169
|
end
|
|
170
|
+
|
|
171
|
+
options
|
|
158
172
|
end
|
|
159
173
|
|
|
160
174
|
# Returns a comment stored in database for given table
|
|
@@ -172,6 +186,36 @@ module ActiveRecord
|
|
|
172
186
|
end
|
|
173
187
|
end
|
|
174
188
|
|
|
189
|
+
# Returns the partition definition of a given table
|
|
190
|
+
def table_partition_definition(table_name) # :nodoc:
|
|
191
|
+
scope = quoted_scope(table_name, type: "BASE TABLE")
|
|
192
|
+
|
|
193
|
+
query_value(<<~SQL, "SCHEMA")
|
|
194
|
+
SELECT pg_catalog.pg_get_partkeydef(c.oid)
|
|
195
|
+
FROM pg_catalog.pg_class c
|
|
196
|
+
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
197
|
+
WHERE c.relname = #{scope[:name]}
|
|
198
|
+
AND c.relkind IN (#{scope[:type]})
|
|
199
|
+
AND n.nspname = #{scope[:schema]}
|
|
200
|
+
SQL
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Returns the inherited table name of a given table
|
|
204
|
+
def inherited_table_names(table_name) # :nodoc:
|
|
205
|
+
scope = quoted_scope(table_name, type: "BASE TABLE")
|
|
206
|
+
|
|
207
|
+
query_values(<<~SQL, "SCHEMA")
|
|
208
|
+
SELECT parent.relname
|
|
209
|
+
FROM pg_catalog.pg_inherits i
|
|
210
|
+
JOIN pg_catalog.pg_class child ON i.inhrelid = child.oid
|
|
211
|
+
JOIN pg_catalog.pg_class parent ON i.inhparent = parent.oid
|
|
212
|
+
LEFT JOIN pg_namespace n ON n.oid = child.relnamespace
|
|
213
|
+
WHERE child.relname = #{scope[:name]}
|
|
214
|
+
AND child.relkind IN (#{scope[:type]})
|
|
215
|
+
AND n.nspname = #{scope[:schema]}
|
|
216
|
+
SQL
|
|
217
|
+
end
|
|
218
|
+
|
|
175
219
|
# Returns the current database name.
|
|
176
220
|
def current_database
|
|
177
221
|
query_value("SELECT current_database()", "SCHEMA")
|
|
@@ -250,13 +294,11 @@ module ActiveRecord
|
|
|
250
294
|
|
|
251
295
|
# Set the client message level.
|
|
252
296
|
def client_min_messages=(level)
|
|
253
|
-
internal_execute("SET client_min_messages TO '#{level}'")
|
|
297
|
+
internal_execute("SET client_min_messages TO '#{level}'", "SCHEMA")
|
|
254
298
|
end
|
|
255
299
|
|
|
256
300
|
# Returns the sequence name for a table's primary key or some other specified key.
|
|
257
301
|
def default_sequence_name(table_name, pk = "id") # :nodoc:
|
|
258
|
-
return nil if pk.is_a?(Array)
|
|
259
|
-
|
|
260
302
|
result = serial_sequence(table_name, pk)
|
|
261
303
|
return nil unless result
|
|
262
304
|
Utils.extract_schema_qualified_name(result).to_s
|
|
@@ -879,7 +921,7 @@ module ActiveRecord
|
|
|
879
921
|
#
|
|
880
922
|
# validate_check_constraint :products, name: "price_check"
|
|
881
923
|
#
|
|
882
|
-
# The +options+ hash accepts the same keys as
|
|
924
|
+
# The +options+ hash accepts the same keys as add_check_constraint[rdoc-ref:ConnectionAdapters::SchemaStatements#add_check_constraint].
|
|
883
925
|
def validate_check_constraint(table_name, **options)
|
|
884
926
|
chk_name_to_validate = check_constraint_for!(table_name, **options).name
|
|
885
927
|
|