activerecord 5.2.4.5 → 6.0.0.beta1
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 +299 -739
- data/MIT-LICENSE +3 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +2 -1
- data/lib/active_record/aggregations.rb +4 -2
- data/lib/active_record/associations.rb +16 -12
- data/lib/active_record/associations/association.rb +35 -19
- data/lib/active_record/associations/association_scope.rb +4 -6
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/belongs_to.rb +14 -50
- data/lib/active_record/associations/builder/collection_association.rb +3 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
- data/lib/active_record/associations/collection_association.rb +11 -25
- data/lib/active_record/associations/collection_proxy.rb +32 -6
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +25 -18
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +15 -20
- data/lib/active_record/associations/join_dependency/join_association.rb +11 -26
- data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
- data/lib/active_record/associations/preloader.rb +32 -29
- data/lib/active_record/associations/preloader/association.rb +1 -2
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/attribute_assignment.rb +7 -10
- data/lib/active_record/attribute_methods.rb +34 -56
- data/lib/active_record/attribute_methods/dirty.rb +64 -26
- data/lib/active_record/attribute_methods/primary_key.rb +8 -7
- data/lib/active_record/attribute_methods/read.rb +16 -48
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attribute_methods/write.rb +15 -16
- data/lib/active_record/autosave_association.rb +7 -21
- data/lib/active_record/base.rb +2 -2
- data/lib/active_record/callbacks.rb +3 -17
- data/lib/active_record/collection_cache_key.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +13 -36
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +25 -84
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +5 -11
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +15 -11
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +0 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +41 -27
- data/lib/active_record/connection_adapters/abstract/transaction.rb +81 -52
- data/lib/active_record/connection_adapters/abstract_adapter.rb +95 -31
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +65 -90
- data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +5 -9
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -7
- data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +65 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -4
- data/lib/active_record/connection_adapters/postgresql/column.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +16 -1
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +11 -36
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +9 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +38 -20
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -56
- data/lib/active_record/connection_adapters/schema_cache.rb +5 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +14 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +95 -62
- data/lib/active_record/connection_handling.rb +132 -26
- data/lib/active_record/core.rb +76 -43
- data/lib/active_record/counter_cache.rb +4 -29
- data/lib/active_record/database_configurations.rb +184 -0
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +74 -0
- data/lib/active_record/enum.rb +22 -7
- data/lib/active_record/errors.rb +24 -21
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixture_set/model_metadata.rb +33 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +153 -0
- data/lib/active_record/fixture_set/table_rows.rb +47 -0
- data/lib/active_record/fixtures.rb +140 -472
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +12 -2
- data/lib/active_record/integration.rb +56 -16
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +2 -2
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +7 -26
- data/lib/active_record/migration.rb +38 -37
- data/lib/active_record/migration/command_recorder.rb +35 -5
- data/lib/active_record/migration/compatibility.rb +34 -16
- data/lib/active_record/model_schema.rb +30 -9
- data/lib/active_record/nested_attributes.rb +2 -2
- data/lib/active_record/no_touching.rb +7 -0
- data/lib/active_record/persistence.rb +18 -7
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +19 -11
- data/lib/active_record/railtie.rb +71 -42
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +94 -43
- data/lib/active_record/reflection.rb +60 -44
- data/lib/active_record/relation.rb +150 -69
- data/lib/active_record/relation/batches.rb +13 -10
- data/lib/active_record/relation/calculations.rb +38 -28
- data/lib/active_record/relation/delegation.rb +4 -13
- data/lib/active_record/relation/finder_methods.rb +12 -25
- data/lib/active_record/relation/merger.rb +2 -6
- data/lib/active_record/relation/predicate_builder.rb +4 -6
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/query_attribute.rb +15 -12
- data/lib/active_record/relation/query_methods.rb +29 -52
- data/lib/active_record/relation/where_clause.rb +4 -0
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/result.rb +30 -11
- data/lib/active_record/sanitization.rb +2 -39
- data/lib/active_record/schema.rb +1 -10
- data/lib/active_record/schema_dumper.rb +12 -6
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping.rb +9 -8
- data/lib/active_record/scoping/default.rb +10 -3
- data/lib/active_record/scoping/named.rb +10 -14
- data/lib/active_record/statement_cache.rb +32 -5
- data/lib/active_record/store.rb +39 -8
- data/lib/active_record/table_metadata.rb +1 -4
- data/lib/active_record/tasks/database_tasks.rb +89 -23
- data/lib/active_record/tasks/mysql_database_tasks.rb +2 -4
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
- data/lib/active_record/test_databases.rb +38 -0
- data/lib/active_record/test_fixtures.rb +224 -0
- data/lib/active_record/timestamp.rb +4 -6
- data/lib/active_record/transactions.rb +3 -22
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type.rb +3 -4
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type_caster/connection.rb +1 -6
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/uniqueness.rb +13 -25
- data/lib/arel.rb +44 -0
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes.rb +67 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +18 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +63 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values.rb +16 -0
- data/lib/arel/nodes/values_list.rb +24 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +257 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/visitors/depth_first.rb +199 -0
- data/lib/arel/visitors/dot.rb +292 -0
- data/lib/arel/visitors/ibm_db.rb +21 -0
- data/lib/arel/visitors/informix.rb +56 -0
- data/lib/arel/visitors/mssql.rb +143 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +159 -0
- data/lib/arel/visitors/oracle12.rb +67 -0
- data/lib/arel/visitors/postgresql.rb +116 -0
- data/lib/arel/visitors/sqlite.rb +39 -0
- data/lib/arel/visitors/to_sql.rb +913 -0
- data/lib/arel/visitors/visitor.rb +42 -0
- data/lib/arel/visitors/where_sql.rb +23 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/rails/generators/active_record/migration.rb +14 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
- metadata +104 -26
@@ -93,11 +93,11 @@ module ActiveRecord
|
|
93
93
|
elsif value.hex?
|
94
94
|
"X'#{value}'"
|
95
95
|
end
|
96
|
-
when
|
97
|
-
if value.
|
98
|
-
"'#{value}'"
|
99
|
-
else
|
96
|
+
when Numeric
|
97
|
+
if value.finite?
|
100
98
|
super
|
99
|
+
else
|
100
|
+
"'#{value}'"
|
101
101
|
end
|
102
102
|
when OID::Array::Data
|
103
103
|
_quote(encode_array(value))
|
@@ -17,48 +17,23 @@ module ActiveRecord
|
|
17
17
|
"VALIDATE CONSTRAINT #{quote_column_name(name)}"
|
18
18
|
end
|
19
19
|
|
20
|
-
def visit_ChangeColumnDefinition(o)
|
21
|
-
column = o.column
|
22
|
-
column.sql_type = type_to_sql(column.type, column.options)
|
23
|
-
quoted_column_name = quote_column_name(o.name)
|
24
|
-
|
25
|
-
change_column_sql = "ALTER COLUMN #{quoted_column_name} TYPE #{column.sql_type}".dup
|
26
|
-
|
27
|
-
options = column_options(column)
|
28
|
-
|
29
|
-
if options[:collation]
|
30
|
-
change_column_sql << " COLLATE \"#{options[:collation]}\""
|
31
|
-
end
|
32
|
-
|
33
|
-
if options[:using]
|
34
|
-
change_column_sql << " USING #{options[:using]}"
|
35
|
-
elsif options[:cast_as]
|
36
|
-
cast_as_type = type_to_sql(options[:cast_as], options)
|
37
|
-
change_column_sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
|
38
|
-
end
|
39
|
-
|
40
|
-
if options.key?(:default)
|
41
|
-
if options[:default].nil?
|
42
|
-
change_column_sql << ", ALTER COLUMN #{quoted_column_name} DROP DEFAULT"
|
43
|
-
else
|
44
|
-
quoted_default = quote_default_expression(options[:default], column)
|
45
|
-
change_column_sql << ", ALTER COLUMN #{quoted_column_name} SET DEFAULT #{quoted_default}"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
if options.key?(:null)
|
50
|
-
change_column_sql << ", ALTER COLUMN #{quoted_column_name} #{options[:null] ? 'DROP' : 'SET'} NOT NULL"
|
51
|
-
end
|
52
|
-
|
53
|
-
change_column_sql
|
54
|
-
end
|
55
|
-
|
56
20
|
def add_column_options!(sql, options)
|
57
21
|
if options[:collation]
|
58
22
|
sql << " COLLATE \"#{options[:collation]}\""
|
59
23
|
end
|
60
24
|
super
|
61
25
|
end
|
26
|
+
|
27
|
+
# Returns any SQL string to go between CREATE and TABLE. May be nil.
|
28
|
+
def table_modifier_in_create(o)
|
29
|
+
# A table cannot be both TEMPORARY and UNLOGGED, since all TEMPORARY
|
30
|
+
# tables are already UNLOGGED.
|
31
|
+
if o.temporary
|
32
|
+
" TEMPORARY"
|
33
|
+
elsif o.unlogged
|
34
|
+
" UNLOGGED"
|
35
|
+
end
|
36
|
+
end
|
62
37
|
end
|
63
38
|
end
|
64
39
|
end
|
@@ -13,10 +13,10 @@ module ActiveRecord
|
|
13
13
|
# t.timestamps
|
14
14
|
# end
|
15
15
|
#
|
16
|
-
# By default, this will use the
|
16
|
+
# By default, this will use the <tt>gen_random_uuid()</tt> function from the
|
17
17
|
# +pgcrypto+ extension. As that extension is only available in
|
18
18
|
# PostgreSQL 9.4+, for earlier versions an explicit default can be set
|
19
|
-
# to use
|
19
|
+
# to use <tt>uuid_generate_v4()</tt> from the +uuid-ossp+ extension instead:
|
20
20
|
#
|
21
21
|
# create_table :stuffs, id: false do |t|
|
22
22
|
# t.primary_key :id, :uuid, default: "uuid_generate_v4()"
|
@@ -175,6 +175,13 @@ module ActiveRecord
|
|
175
175
|
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
176
176
|
include ColumnMethods
|
177
177
|
|
178
|
+
attr_reader :unlogged
|
179
|
+
|
180
|
+
def initialize(*)
|
181
|
+
super
|
182
|
+
@unlogged = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables
|
183
|
+
end
|
184
|
+
|
178
185
|
private
|
179
186
|
def integer_like_primary_key_type(type, options)
|
180
187
|
if type == :bigint || options[:limit] == 8
|
@@ -22,8 +22,8 @@ module ActiveRecord
|
|
22
22
|
def create_database(name, options = {})
|
23
23
|
options = { encoding: "utf8" }.merge!(options.symbolize_keys)
|
24
24
|
|
25
|
-
option_string = options.
|
26
|
-
memo
|
25
|
+
option_string = options.each_with_object(+"") do |(key, value), memo|
|
26
|
+
memo << case key
|
27
27
|
when :owner
|
28
28
|
" OWNER = \"#{value}\""
|
29
29
|
when :template
|
@@ -68,7 +68,7 @@ module ActiveRecord
|
|
68
68
|
table = quoted_scope(table_name)
|
69
69
|
index = quoted_scope(index_name)
|
70
70
|
|
71
|
-
query_value(
|
71
|
+
query_value(<<~SQL, "SCHEMA").to_i > 0
|
72
72
|
SELECT COUNT(*)
|
73
73
|
FROM pg_class t
|
74
74
|
INNER JOIN pg_index d ON t.oid = d.indrelid
|
@@ -85,7 +85,7 @@ module ActiveRecord
|
|
85
85
|
def indexes(table_name) # :nodoc:
|
86
86
|
scope = quoted_scope(table_name)
|
87
87
|
|
88
|
-
result = query(
|
88
|
+
result = query(<<~SQL, "SCHEMA")
|
89
89
|
SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid,
|
90
90
|
pg_catalog.obj_description(i.oid, 'pg_class') AS comment
|
91
91
|
FROM pg_class t
|
@@ -115,7 +115,7 @@ module ActiveRecord
|
|
115
115
|
if indkey.include?(0)
|
116
116
|
columns = expressions
|
117
117
|
else
|
118
|
-
columns = Hash[query(
|
118
|
+
columns = Hash[query(<<~SQL, "SCHEMA")].values_at(*indkey).compact
|
119
119
|
SELECT a.attnum, a.attname
|
120
120
|
FROM pg_attribute a
|
121
121
|
WHERE a.attrelid = #{oid}
|
@@ -158,7 +158,7 @@ module ActiveRecord
|
|
158
158
|
def table_comment(table_name) # :nodoc:
|
159
159
|
scope = quoted_scope(table_name, type: "BASE TABLE")
|
160
160
|
if scope[:name]
|
161
|
-
query_value(
|
161
|
+
query_value(<<~SQL, "SCHEMA")
|
162
162
|
SELECT pg_catalog.obj_description(c.oid, 'pg_class')
|
163
163
|
FROM pg_catalog.pg_class c
|
164
164
|
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
@@ -196,7 +196,7 @@ module ActiveRecord
|
|
196
196
|
|
197
197
|
# Returns an array of schema names.
|
198
198
|
def schema_names
|
199
|
-
query_values(
|
199
|
+
query_values(<<~SQL, "SCHEMA")
|
200
200
|
SELECT nspname
|
201
201
|
FROM pg_namespace
|
202
202
|
WHERE nspname !~ '^pg_.*'
|
@@ -302,7 +302,7 @@ module ActiveRecord
|
|
302
302
|
def pk_and_sequence_for(table) #:nodoc:
|
303
303
|
# First try looking for a sequence with a dependency on the
|
304
304
|
# given table's primary key.
|
305
|
-
result = query(
|
305
|
+
result = query(<<~SQL, "SCHEMA")[0]
|
306
306
|
SELECT attr.attname, nsp.nspname, seq.relname
|
307
307
|
FROM pg_class seq,
|
308
308
|
pg_attribute attr,
|
@@ -319,10 +319,10 @@ module ActiveRecord
|
|
319
319
|
AND cons.contype = 'p'
|
320
320
|
AND dep.classid = 'pg_class'::regclass
|
321
321
|
AND dep.refobjid = #{quote(quote_table_name(table))}::regclass
|
322
|
-
|
322
|
+
SQL
|
323
323
|
|
324
324
|
if result.nil? || result.empty?
|
325
|
-
result = query(
|
325
|
+
result = query(<<~SQL, "SCHEMA")[0]
|
326
326
|
SELECT attr.attname, nsp.nspname,
|
327
327
|
CASE
|
328
328
|
WHEN pg_get_expr(def.adbin, def.adrelid) !~* 'nextval' THEN NULL
|
@@ -339,7 +339,7 @@ module ActiveRecord
|
|
339
339
|
WHERE t.oid = #{quote(quote_table_name(table))}::regclass
|
340
340
|
AND cons.contype = 'p'
|
341
341
|
AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval|uuid_generate'
|
342
|
-
|
342
|
+
SQL
|
343
343
|
end
|
344
344
|
|
345
345
|
pk = result.shift
|
@@ -353,7 +353,7 @@ module ActiveRecord
|
|
353
353
|
end
|
354
354
|
|
355
355
|
def primary_keys(table_name) # :nodoc:
|
356
|
-
query_values(
|
356
|
+
query_values(<<~SQL, "SCHEMA")
|
357
357
|
SELECT a.attname
|
358
358
|
FROM (
|
359
359
|
SELECT indrelid, indkey, generate_subscripts(indkey, 1) idx
|
@@ -502,7 +502,7 @@ module ActiveRecord
|
|
502
502
|
|
503
503
|
def foreign_keys(table_name)
|
504
504
|
scope = quoted_scope(table_name)
|
505
|
-
fk_info = exec_query(
|
505
|
+
fk_info = exec_query(<<~SQL, "SCHEMA")
|
506
506
|
SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete, c.convalidated AS valid
|
507
507
|
FROM pg_constraint c
|
508
508
|
JOIN pg_class t1 ON c.conrelid = t1.oid
|
@@ -683,20 +683,38 @@ module ActiveRecord
|
|
683
683
|
end
|
684
684
|
end
|
685
685
|
|
686
|
+
def change_column_sql(table_name, column_name, type, options = {})
|
687
|
+
quoted_column_name = quote_column_name(column_name)
|
688
|
+
sql_type = type_to_sql(type, options)
|
689
|
+
sql = +"ALTER COLUMN #{quoted_column_name} TYPE #{sql_type}"
|
690
|
+
if options[:collation]
|
691
|
+
sql << " COLLATE \"#{options[:collation]}\""
|
692
|
+
end
|
693
|
+
if options[:using]
|
694
|
+
sql << " USING #{options[:using]}"
|
695
|
+
elsif options[:cast_as]
|
696
|
+
cast_as_type = type_to_sql(options[:cast_as], options)
|
697
|
+
sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
|
698
|
+
end
|
699
|
+
|
700
|
+
sql
|
701
|
+
end
|
702
|
+
|
686
703
|
def add_column_for_alter(table_name, column_name, type, options = {})
|
687
704
|
return super unless options.key?(:comment)
|
688
705
|
[super, Proc.new { change_column_comment(table_name, column_name, options[:comment]) }]
|
689
706
|
end
|
690
707
|
|
691
708
|
def change_column_for_alter(table_name, column_name, type, options = {})
|
692
|
-
|
693
|
-
|
694
|
-
sqls
|
709
|
+
sqls = [change_column_sql(table_name, column_name, type, options)]
|
710
|
+
sqls << change_column_default_for_alter(table_name, column_name, options[:default]) if options.key?(:default)
|
711
|
+
sqls << change_column_null_for_alter(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
|
695
712
|
sqls << Proc.new { change_column_comment(table_name, column_name, options[:comment]) } if options.key?(:comment)
|
696
713
|
sqls
|
697
714
|
end
|
698
715
|
|
699
|
-
|
716
|
+
# Changes the default value of a table column.
|
717
|
+
def change_column_default_for_alter(table_name, column_name, default_or_changes) # :nodoc:
|
700
718
|
column = column_for(table_name, column_name)
|
701
719
|
return unless column
|
702
720
|
|
@@ -711,8 +729,8 @@ module ActiveRecord
|
|
711
729
|
end
|
712
730
|
end
|
713
731
|
|
714
|
-
def change_column_null_for_alter(table_name, column_name, null, default = nil)
|
715
|
-
"ALTER
|
732
|
+
def change_column_null_for_alter(table_name, column_name, null, default = nil) #:nodoc:
|
733
|
+
"ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL"
|
716
734
|
end
|
717
735
|
|
718
736
|
def add_timestamps_for_alter(table_name, options = {})
|
@@ -739,7 +757,7 @@ module ActiveRecord
|
|
739
757
|
scope = quoted_scope(name, type: type)
|
740
758
|
scope[:type] ||= "'r','v','m','p','f'" # (r)elation/table, (v)iew, (m)aterialized view, (p)artitioned table, (f)oreign table
|
741
759
|
|
742
|
-
sql = "SELECT c.relname FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace"
|
760
|
+
sql = +"SELECT c.relname FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace"
|
743
761
|
sql << " WHERE n.nspname = #{scope[:schema]}"
|
744
762
|
sql << " AND c.relname = #{scope[:name]}" if scope[:name]
|
745
763
|
sql << " AND c.relkind IN (#{scope[:type]})"
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
|
+
# :stopdoc:
|
4
5
|
module ConnectionAdapters
|
5
6
|
class PostgreSQLTypeMetadata < DelegateClass(SqlTypeMetadata)
|
6
7
|
undef to_yaml if method_defined?(:to_yaml)
|
@@ -16,7 +17,7 @@ module ActiveRecord
|
|
16
17
|
end
|
17
18
|
|
18
19
|
def sql_type
|
19
|
-
super.gsub(/\[\]$/, ""
|
20
|
+
super.gsub(/\[\]$/, "")
|
20
21
|
end
|
21
22
|
|
22
23
|
def ==(other)
|
@@ -5,7 +5,7 @@ gem "pg", ">= 0.18", "< 2.0"
|
|
5
5
|
require "pg"
|
6
6
|
|
7
7
|
# Use async_exec instead of exec_params on pg versions before 1.1
|
8
|
-
class ::PG::Connection
|
8
|
+
class ::PG::Connection # :nodoc:
|
9
9
|
unless self.public_method_defined?(:async_exec_params)
|
10
10
|
remove_method :exec_params
|
11
11
|
alias exec_params async_exec
|
@@ -43,9 +43,14 @@ module ActiveRecord
|
|
43
43
|
valid_conn_param_keys = PG::Connection.conndefaults_hash.keys + [:requiressl]
|
44
44
|
conn_params.slice!(*valid_conn_param_keys)
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
conn = PG.connect(conn_params)
|
47
|
+
ConnectionAdapters::PostgreSQLAdapter.new(conn, logger, conn_params, config)
|
48
|
+
rescue ::PG::Error => error
|
49
|
+
if error.message.include?("does not exist")
|
50
|
+
raise ActiveRecord::NoDatabaseError
|
51
|
+
else
|
52
|
+
raise
|
53
|
+
end
|
49
54
|
end
|
50
55
|
end
|
51
56
|
|
@@ -78,7 +83,20 @@ module ActiveRecord
|
|
78
83
|
# In addition, default connection parameters of libpq can be set per environment variables.
|
79
84
|
# See https://www.postgresql.org/docs/current/static/libpq-envars.html .
|
80
85
|
class PostgreSQLAdapter < AbstractAdapter
|
81
|
-
ADAPTER_NAME = "PostgreSQL"
|
86
|
+
ADAPTER_NAME = "PostgreSQL"
|
87
|
+
|
88
|
+
##
|
89
|
+
# :singleton-method:
|
90
|
+
# PostgreSQL allows the creation of "unlogged" tables, which do not record
|
91
|
+
# data in the PostgreSQL Write-Ahead Log. This can make the tables faster,
|
92
|
+
# but significantly increases the risk of data loss if the database
|
93
|
+
# crashes. As a result, this should not be used in production
|
94
|
+
# environments. If you would like all created tables to be unlogged in
|
95
|
+
# the test environment you can add the following line to your test.rb
|
96
|
+
# file:
|
97
|
+
#
|
98
|
+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true
|
99
|
+
class_attribute :create_unlogged_tables, default: false
|
82
100
|
|
83
101
|
NATIVE_DATABASE_TYPES = {
|
84
102
|
primary_key: "bigserial primary key",
|
@@ -167,7 +185,7 @@ module ActiveRecord
|
|
167
185
|
end
|
168
186
|
|
169
187
|
def supports_json?
|
170
|
-
|
188
|
+
true
|
171
189
|
end
|
172
190
|
|
173
191
|
def supports_comments?
|
@@ -220,15 +238,11 @@ module ActiveRecord
|
|
220
238
|
@local_tz = nil
|
221
239
|
@max_identifier_length = nil
|
222
240
|
|
223
|
-
|
241
|
+
configure_connection
|
224
242
|
add_pg_encoders
|
225
243
|
@statements = StatementPool.new @connection,
|
226
244
|
self.class.type_cast_config_to_integer(config[:statement_limit])
|
227
245
|
|
228
|
-
if postgresql_version < 90100
|
229
|
-
raise "Your version of PostgreSQL (#{postgresql_version}) is too old. Active Record supports PostgreSQL >= 9.1."
|
230
|
-
end
|
231
|
-
|
232
246
|
add_pg_decoders
|
233
247
|
|
234
248
|
@type_map = Type::HashLookupTypeMap.new
|
@@ -318,22 +332,26 @@ module ActiveRecord
|
|
318
332
|
end
|
319
333
|
|
320
334
|
def supports_ranges?
|
321
|
-
|
322
|
-
postgresql_version >= 90200
|
335
|
+
true
|
323
336
|
end
|
337
|
+
deprecate :supports_ranges?
|
324
338
|
|
325
339
|
def supports_materialized_views?
|
326
|
-
|
340
|
+
true
|
327
341
|
end
|
328
342
|
|
329
343
|
def supports_foreign_tables?
|
330
|
-
|
344
|
+
true
|
331
345
|
end
|
332
346
|
|
333
347
|
def supports_pgcrypto_uuid?
|
334
348
|
postgresql_version >= 90400
|
335
349
|
end
|
336
350
|
|
351
|
+
def supports_lazy_transactions?
|
352
|
+
true
|
353
|
+
end
|
354
|
+
|
337
355
|
def get_advisory_lock(lock_id) # :nodoc:
|
338
356
|
unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63
|
339
357
|
raise(ArgumentError, "PostgreSQL requires advisory lock ids to be a signed 64 bit integer")
|
@@ -406,6 +424,12 @@ module ActiveRecord
|
|
406
424
|
end
|
407
425
|
|
408
426
|
private
|
427
|
+
def check_version
|
428
|
+
if postgresql_version < 90300
|
429
|
+
raise "Your version of PostgreSQL (#{postgresql_version}) is too old. Active Record supports PostgreSQL >= 9.3."
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
409
433
|
# See https://www.postgresql.org/docs/current/static/errcodes-appendix.html
|
410
434
|
VALUE_LIMIT_VIOLATION = "22001"
|
411
435
|
NUMERIC_VALUE_OUT_OF_RANGE = "22003"
|
@@ -417,34 +441,34 @@ module ActiveRecord
|
|
417
441
|
LOCK_NOT_AVAILABLE = "55P03"
|
418
442
|
QUERY_CANCELED = "57014"
|
419
443
|
|
420
|
-
def translate_exception(exception, message)
|
444
|
+
def translate_exception(exception, message:, sql:, binds:)
|
421
445
|
return exception unless exception.respond_to?(:result)
|
422
446
|
|
423
447
|
case exception.result.try(:error_field, PG::PG_DIAG_SQLSTATE)
|
424
448
|
when UNIQUE_VIOLATION
|
425
|
-
RecordNotUnique.new(message)
|
449
|
+
RecordNotUnique.new(message, sql: sql, binds: binds)
|
426
450
|
when FOREIGN_KEY_VIOLATION
|
427
|
-
InvalidForeignKey.new(message)
|
451
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
428
452
|
when VALUE_LIMIT_VIOLATION
|
429
|
-
ValueTooLong.new(message)
|
453
|
+
ValueTooLong.new(message, sql: sql, binds: binds)
|
430
454
|
when NUMERIC_VALUE_OUT_OF_RANGE
|
431
|
-
RangeError.new(message)
|
455
|
+
RangeError.new(message, sql: sql, binds: binds)
|
432
456
|
when NOT_NULL_VIOLATION
|
433
|
-
NotNullViolation.new(message)
|
457
|
+
NotNullViolation.new(message, sql: sql, binds: binds)
|
434
458
|
when SERIALIZATION_FAILURE
|
435
|
-
SerializationFailure.new(message)
|
459
|
+
SerializationFailure.new(message, sql: sql, binds: binds)
|
436
460
|
when DEADLOCK_DETECTED
|
437
|
-
Deadlocked.new(message)
|
461
|
+
Deadlocked.new(message, sql: sql, binds: binds)
|
438
462
|
when LOCK_NOT_AVAILABLE
|
439
|
-
LockWaitTimeout.new(message)
|
463
|
+
LockWaitTimeout.new(message, sql: sql, binds: binds)
|
440
464
|
when QUERY_CANCELED
|
441
|
-
QueryCanceled.new(message)
|
465
|
+
QueryCanceled.new(message, sql: sql, binds: binds)
|
442
466
|
else
|
443
467
|
super
|
444
468
|
end
|
445
469
|
end
|
446
470
|
|
447
|
-
def get_oid_type(oid, fmod, column_name, sql_type = ""
|
471
|
+
def get_oid_type(oid, fmod, column_name, sql_type = "")
|
448
472
|
if !type_map.key?(oid)
|
449
473
|
load_additional_types([oid])
|
450
474
|
end
|
@@ -533,13 +557,13 @@ module ActiveRecord
|
|
533
557
|
# Quoted types
|
534
558
|
when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
|
535
559
|
# The default 'now'::date is CURRENT_DATE
|
536
|
-
if $1 == "now"
|
560
|
+
if $1 == "now" && $2 == "date"
|
537
561
|
nil
|
538
562
|
else
|
539
|
-
$1.gsub("''"
|
563
|
+
$1.gsub("''", "'")
|
540
564
|
end
|
541
565
|
# Boolean types
|
542
|
-
when "true"
|
566
|
+
when "true", "false"
|
543
567
|
default
|
544
568
|
# Numeric types
|
545
569
|
when /\A\(?(-?\d+(\.\d*)?)\)?(::bigint)?\z/
|
@@ -565,18 +589,11 @@ module ActiveRecord
|
|
565
589
|
def load_additional_types(oids = nil)
|
566
590
|
initializer = OID::TypeMapInitializer.new(type_map)
|
567
591
|
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
SQL
|
574
|
-
else
|
575
|
-
query = <<-SQL
|
576
|
-
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, t.typtype, t.typbasetype
|
577
|
-
FROM pg_type as t
|
578
|
-
SQL
|
579
|
-
end
|
592
|
+
query = <<~SQL
|
593
|
+
SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype, t.typtype, t.typbasetype
|
594
|
+
FROM pg_type as t
|
595
|
+
LEFT JOIN pg_range as r ON oid = rngtypid
|
596
|
+
SQL
|
580
597
|
|
581
598
|
if oids
|
582
599
|
query += "WHERE t.oid::integer IN (%s)" % oids.join(", ")
|
@@ -592,6 +609,10 @@ module ActiveRecord
|
|
592
609
|
FEATURE_NOT_SUPPORTED = "0A000" #:nodoc:
|
593
610
|
|
594
611
|
def execute_and_clear(sql, name, binds, prepare: false)
|
612
|
+
if preventing_writes? && write_query?(sql)
|
613
|
+
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
614
|
+
end
|
615
|
+
|
595
616
|
if without_prepared_statement?(binds)
|
596
617
|
result = exec_no_cache(sql, name, [])
|
597
618
|
elsif !prepare
|
@@ -605,6 +626,8 @@ module ActiveRecord
|
|
605
626
|
end
|
606
627
|
|
607
628
|
def exec_no_cache(sql, name, binds)
|
629
|
+
materialize_transactions
|
630
|
+
|
608
631
|
type_casted_binds = type_casted_binds(binds)
|
609
632
|
log(sql, name, binds, type_casted_binds) do
|
610
633
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
|
@@ -614,7 +637,9 @@ module ActiveRecord
|
|
614
637
|
end
|
615
638
|
|
616
639
|
def exec_cache(sql, name, binds)
|
617
|
-
|
640
|
+
materialize_transactions
|
641
|
+
|
642
|
+
stmt_key = prepare_statement(sql, binds)
|
618
643
|
type_casted_binds = type_casted_binds(binds)
|
619
644
|
|
620
645
|
log(sql, name, binds, type_casted_binds, stmt_key) do
|
@@ -647,7 +672,7 @@ module ActiveRecord
|
|
647
672
|
#
|
648
673
|
# Check here for more details:
|
649
674
|
# https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
|
650
|
-
CACHED_PLAN_HEURISTIC = "cached plan must not change result type"
|
675
|
+
CACHED_PLAN_HEURISTIC = "cached plan must not change result type"
|
651
676
|
def is_cached_plan_failure?(e)
|
652
677
|
pgerror = e.cause
|
653
678
|
code = pgerror.result.result_error_field(PG::PG_DIAG_SQLSTATE)
|
@@ -668,7 +693,7 @@ module ActiveRecord
|
|
668
693
|
|
669
694
|
# Prepare the statement if it hasn't been prepared, return
|
670
695
|
# the statement key.
|
671
|
-
def prepare_statement(sql)
|
696
|
+
def prepare_statement(sql, binds)
|
672
697
|
@lock.synchronize do
|
673
698
|
sql_key = sql_key(sql)
|
674
699
|
unless @statements.key? sql_key
|
@@ -676,7 +701,7 @@ module ActiveRecord
|
|
676
701
|
begin
|
677
702
|
@connection.prepare nextkey, sql
|
678
703
|
rescue => e
|
679
|
-
raise translate_exception_class(e, sql)
|
704
|
+
raise translate_exception_class(e, sql, binds)
|
680
705
|
end
|
681
706
|
# Clear the queue
|
682
707
|
@connection.get_last_result
|
@@ -691,12 +716,6 @@ module ActiveRecord
|
|
691
716
|
def connect
|
692
717
|
@connection = PG.connect(@connection_parameters)
|
693
718
|
configure_connection
|
694
|
-
rescue ::PG::Error => error
|
695
|
-
if error.message.include?("does not exist")
|
696
|
-
raise ActiveRecord::NoDatabaseError
|
697
|
-
else
|
698
|
-
raise
|
699
|
-
end
|
700
719
|
end
|
701
720
|
|
702
721
|
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
|
@@ -754,7 +773,7 @@ module ActiveRecord
|
|
754
773
|
# - format_type includes the column size constraint, e.g. varchar(50)
|
755
774
|
# - ::regclass is a function that gives the id for a table name
|
756
775
|
def column_definitions(table_name)
|
757
|
-
query(
|
776
|
+
query(<<~SQL, "SCHEMA")
|
758
777
|
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
|
759
778
|
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
|
760
779
|
c.collname, col_description(a.attrelid, a.attnum) AS comment
|
@@ -765,7 +784,7 @@ module ActiveRecord
|
|
765
784
|
WHERE a.attrelid = #{quote(quote_table_name(table_name))}::regclass
|
766
785
|
AND a.attnum > 0 AND NOT a.attisdropped
|
767
786
|
ORDER BY a.attnum
|
768
|
-
|
787
|
+
SQL
|
769
788
|
end
|
770
789
|
|
771
790
|
def extract_table_ref_from_insert_sql(sql)
|
@@ -780,7 +799,7 @@ module ActiveRecord
|
|
780
799
|
def can_perform_case_insensitive_comparison_for?(column)
|
781
800
|
@case_insensitive_cache ||= {}
|
782
801
|
@case_insensitive_cache[column.sql_type] ||= begin
|
783
|
-
sql =
|
802
|
+
sql = <<~SQL
|
784
803
|
SELECT exists(
|
785
804
|
SELECT * FROM pg_proc
|
786
805
|
WHERE proname = 'lower'
|
@@ -792,7 +811,7 @@ module ActiveRecord
|
|
792
811
|
WHERE proname = 'lower'
|
793
812
|
AND castsource = #{quote column.sql_type}::regtype
|
794
813
|
)
|
795
|
-
|
814
|
+
SQL
|
796
815
|
execute_and_clear(sql, "SCHEMA", []) do |result|
|
797
816
|
result.getvalue(0, 0)
|
798
817
|
end
|
@@ -818,7 +837,7 @@ module ActiveRecord
|
|
818
837
|
"bool" => PG::TextDecoder::Boolean,
|
819
838
|
}
|
820
839
|
known_coder_types = coders_by_name.keys.map { |n| quote(n) }
|
821
|
-
query =
|
840
|
+
query = <<~SQL % known_coder_types.join(", ")
|
822
841
|
SELECT t.oid, t.typname
|
823
842
|
FROM pg_type as t
|
824
843
|
WHERE t.typname IN (%s)
|