activerecord 6.0.0.beta3 → 6.0.2.rc2
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 +466 -9
- data/README.rdoc +3 -1
- data/lib/active_record.rb +0 -1
- data/lib/active_record/association_relation.rb +15 -6
- data/lib/active_record/associations.rb +4 -3
- data/lib/active_record/associations/association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +5 -2
- data/lib/active_record/associations/builder/collection_association.rb +5 -15
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +6 -2
- data/lib/active_record/associations/collection_proxy.rb +2 -2
- data/lib/active_record/associations/has_many_through_association.rb +4 -11
- data/lib/active_record/associations/join_dependency.rb +14 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +12 -3
- data/lib/active_record/associations/preloader.rb +13 -8
- data/lib/active_record/associations/preloader/association.rb +34 -30
- data/lib/active_record/associations/preloader/through_association.rb +48 -28
- data/lib/active_record/attribute_methods.rb +3 -53
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
- data/lib/active_record/attribute_methods/dirty.rb +47 -14
- data/lib/active_record/attribute_methods/primary_key.rb +7 -15
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +3 -9
- data/lib/active_record/attribute_methods/write.rb +6 -12
- data/lib/active_record/attributes.rb +13 -0
- data/lib/active_record/autosave_association.rb +21 -7
- data/lib/active_record/base.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -11
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +88 -61
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +6 -4
- data/lib/active_record/connection_adapters/abstract/quoting.rb +63 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -7
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +79 -22
- data/lib/active_record/connection_adapters/abstract/transaction.rb +12 -4
- data/lib/active_record/connection_adapters/abstract_adapter.rb +111 -33
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +78 -73
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -2
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +48 -8
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -5
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +9 -6
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +18 -5
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +39 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +34 -38
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +67 -26
- data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -2
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -114
- data/lib/active_record/connection_handling.rb +31 -13
- data/lib/active_record/core.rb +23 -24
- data/lib/active_record/database_configurations.rb +73 -44
- data/lib/active_record/database_configurations/hash_config.rb +11 -11
- data/lib/active_record/database_configurations/url_config.rb +12 -12
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/enum.rb +15 -0
- data/lib/active_record/errors.rb +1 -1
- data/lib/active_record/fixtures.rb +11 -6
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +13 -1
- data/lib/active_record/internal_metadata.rb +5 -1
- data/lib/active_record/locking/optimistic.rb +3 -4
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/middleware/database_selector.rb +3 -3
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -6
- data/lib/active_record/migration.rb +62 -44
- data/lib/active_record/migration/command_recorder.rb +28 -14
- data/lib/active_record/migration/compatibility.rb +10 -0
- data/lib/active_record/model_schema.rb +3 -0
- data/lib/active_record/persistence.rb +206 -13
- data/lib/active_record/querying.rb +17 -12
- data/lib/active_record/railtie.rb +0 -1
- data/lib/active_record/railties/databases.rake +127 -25
- data/lib/active_record/reflection.rb +3 -3
- data/lib/active_record/relation.rb +99 -20
- data/lib/active_record/relation/calculations.rb +38 -40
- data/lib/active_record/relation/delegation.rb +22 -30
- data/lib/active_record/relation/finder_methods.rb +17 -12
- data/lib/active_record/relation/merger.rb +11 -16
- data/lib/active_record/relation/query_methods.rb +228 -76
- data/lib/active_record/relation/where_clause.rb +9 -5
- data/lib/active_record/sanitization.rb +33 -4
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +10 -1
- data/lib/active_record/schema_migration.rb +1 -1
- data/lib/active_record/scoping/default.rb +6 -7
- data/lib/active_record/scoping/named.rb +3 -2
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/store.rb +48 -0
- data/lib/active_record/table_metadata.rb +9 -13
- data/lib/active_record/tasks/database_tasks.rb +109 -6
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -1
- data/lib/active_record/test_databases.rb +1 -16
- data/lib/active_record/test_fixtures.rb +1 -0
- data/lib/active_record/timestamp.rb +26 -16
- data/lib/active_record/touch_later.rb +4 -2
- data/lib/active_record/transactions.rb +56 -46
- data/lib/active_record/type_caster/connection.rb +16 -10
- data/lib/active_record/validations.rb +1 -0
- data/lib/active_record/validations/uniqueness.rb +3 -5
- data/lib/arel.rb +12 -5
- data/lib/arel/insert_manager.rb +3 -3
- data/lib/arel/nodes.rb +2 -1
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/select_core.rb +16 -12
- data/lib/arel/nodes/unary.rb +1 -0
- data/lib/arel/nodes/values_list.rb +2 -17
- data/lib/arel/select_manager.rb +10 -10
- data/lib/arel/visitors/depth_first.rb +7 -2
- data/lib/arel/visitors/dot.rb +7 -2
- data/lib/arel/visitors/ibm_db.rb +13 -0
- data/lib/arel/visitors/informix.rb +6 -0
- data/lib/arel/visitors/mssql.rb +15 -1
- data/lib/arel/visitors/oracle12.rb +4 -5
- data/lib/arel/visitors/postgresql.rb +4 -10
- data/lib/arel/visitors/to_sql.rb +107 -131
- data/lib/arel/visitors/visitor.rb +9 -5
- data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +16 -12
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/arel/nodes/values.rb +0 -16
@@ -2,42 +2,29 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module ConnectionAdapters
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
alias :array? :array
|
5
|
+
module PostgreSQL
|
6
|
+
class Column < ConnectionAdapters::Column # :nodoc:
|
7
|
+
delegate :oid, :fmod, to: :sql_type_metadata
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
def serial?
|
16
|
-
return unless default_function
|
17
|
-
|
18
|
-
if %r{\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z} =~ default_function
|
19
|
-
sequence_name_from_parts(table_name, name, suffix) == sequence_name
|
9
|
+
def initialize(*, serial: nil, **)
|
10
|
+
super
|
11
|
+
@serial = serial
|
20
12
|
end
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
attr_reader :max_identifier_length
|
25
13
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
if over_length > 0
|
30
|
-
column_name_length = [(max_identifier_length - suffix.length - 2) / 2, column_name.length].min
|
31
|
-
over_length -= column_name.length - column_name_length
|
32
|
-
column_name = column_name[0, column_name_length - [over_length, 0].min]
|
33
|
-
end
|
14
|
+
def serial?
|
15
|
+
@serial
|
16
|
+
end
|
34
17
|
|
35
|
-
|
36
|
-
|
37
|
-
|
18
|
+
def array
|
19
|
+
sql_type_metadata.sql_type.end_with?("[]")
|
20
|
+
end
|
21
|
+
alias :array? :array
|
38
22
|
|
39
|
-
|
23
|
+
def sql_type
|
24
|
+
super.sub(/\[\]\z/, "")
|
40
25
|
end
|
26
|
+
end
|
41
27
|
end
|
28
|
+
PostgreSQLColumn = PostgreSQL::Column # :nodoc:
|
42
29
|
end
|
43
30
|
end
|
@@ -67,7 +67,9 @@ module ActiveRecord
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
70
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
71
|
+
:begin, :commit, :explain, :select, :set, :show, :release, :savepoint, :rollback, :with
|
72
|
+
) # :nodoc:
|
71
73
|
private_constant :READ_QUERY
|
72
74
|
|
73
75
|
def write_query?(sql) # :nodoc:
|
@@ -110,7 +112,7 @@ module ActiveRecord
|
|
110
112
|
end
|
111
113
|
alias :exec_update :exec_delete
|
112
114
|
|
113
|
-
def sql_for_insert(sql, pk,
|
115
|
+
def sql_for_insert(sql, pk, binds) # :nodoc:
|
114
116
|
if pk.nil?
|
115
117
|
# Extract the table from the insert sql. Yuck.
|
116
118
|
table_ref = extract_table_ref_from_insert_sql(sql)
|
@@ -164,6 +166,10 @@ module ActiveRecord
|
|
164
166
|
end
|
165
167
|
|
166
168
|
private
|
169
|
+
def build_truncate_statements(*table_names)
|
170
|
+
"TRUNCATE TABLE #{table_names.map(&method(:quote_table_name)).join(", ")}"
|
171
|
+
end
|
172
|
+
|
167
173
|
# Returns the current ID of a table's sequence.
|
168
174
|
def last_insert_id_result(sequence_name)
|
169
175
|
exec_query("SELECT currval(#{quote(sequence_name)})", "SQL")
|
@@ -26,9 +26,9 @@ module ActiveRecord
|
|
26
26
|
|
27
27
|
value = value.sub(/^\((.+)\)$/, '-\1') # (4)
|
28
28
|
case value
|
29
|
-
when /^-?\D
|
29
|
+
when /^-?\D*[\d,]+\.\d{2}$/ # (1)
|
30
30
|
value.gsub!(/[^-\d.]/, "")
|
31
|
-
when /^-?\D
|
31
|
+
when /^-?\D*[\d.]+,\d{2}$/ # (2)
|
32
32
|
value.gsub!(/[^-\d,]/, "").sub!(/,/, ".")
|
33
33
|
end
|
34
34
|
|
@@ -30,7 +30,7 @@ module ActiveRecord
|
|
30
30
|
# - "schema.name".table_name
|
31
31
|
# - "schema.name"."table.name"
|
32
32
|
def quote_table_name(name) # :nodoc:
|
33
|
-
|
33
|
+
self.class.quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze
|
34
34
|
end
|
35
35
|
|
36
36
|
# Quotes schema names for use in SQL queries.
|
@@ -44,7 +44,7 @@ module ActiveRecord
|
|
44
44
|
|
45
45
|
# Quotes column names for use in SQL queries.
|
46
46
|
def quote_column_name(name) # :nodoc:
|
47
|
-
|
47
|
+
self.class.quoted_column_names[name] ||= PG::Connection.quote_ident(super).freeze
|
48
48
|
end
|
49
49
|
|
50
50
|
# Quote date/time values for use in SQL input.
|
@@ -78,6 +78,43 @@ module ActiveRecord
|
|
78
78
|
type_map.lookup(column.oid, column.fmod, column.sql_type)
|
79
79
|
end
|
80
80
|
|
81
|
+
def column_name_matcher
|
82
|
+
COLUMN_NAME
|
83
|
+
end
|
84
|
+
|
85
|
+
def column_name_with_order_matcher
|
86
|
+
COLUMN_NAME_WITH_ORDER
|
87
|
+
end
|
88
|
+
|
89
|
+
COLUMN_NAME = /
|
90
|
+
\A
|
91
|
+
(
|
92
|
+
(?:
|
93
|
+
# "table_name"."column_name"::type_name | function(one or no argument)::type_name
|
94
|
+
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
|
95
|
+
)
|
96
|
+
(?:\s+AS\s+(?:\w+|"\w+"))?
|
97
|
+
)
|
98
|
+
(?:\s*,\s*\g<1>)*
|
99
|
+
\z
|
100
|
+
/ix
|
101
|
+
|
102
|
+
COLUMN_NAME_WITH_ORDER = /
|
103
|
+
\A
|
104
|
+
(
|
105
|
+
(?:
|
106
|
+
# "table_name"."column_name"::type_name | function(one or no argument)::type_name
|
107
|
+
((?:\w+\.|"\w+"\.)?(?:\w+|"\w+")(?:::\w+)?) | \w+\((?:|\g<2>)\)(?:::\w+)?
|
108
|
+
)
|
109
|
+
(?:\s+ASC|\s+DESC)?
|
110
|
+
(?:\s+NULLS\s+(?:FIRST|LAST))?
|
111
|
+
)
|
112
|
+
(?:\s*,\s*\g<1>)*
|
113
|
+
\z
|
114
|
+
/ix
|
115
|
+
|
116
|
+
private_constant :COLUMN_NAME, :COLUMN_NAME_WITH_ORDER
|
117
|
+
|
81
118
|
private
|
82
119
|
def lookup_cast_type(sql_type)
|
83
120
|
super(query_value("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").to_i)
|
@@ -287,7 +287,7 @@ module ActiveRecord
|
|
287
287
|
quoted_sequence = quote_table_name(sequence)
|
288
288
|
max_pk = query_value("SELECT MAX(#{quote_column_name pk}) FROM #{quote_table_name(table)}", "SCHEMA")
|
289
289
|
if max_pk.nil?
|
290
|
-
if
|
290
|
+
if database_version >= 100000
|
291
291
|
minvalue = query_value("SELECT seqmin FROM pg_sequence WHERE seqrelid = #{quote(quoted_sequence)}::regclass", "SCHEMA")
|
292
292
|
else
|
293
293
|
minvalue = query_value("SELECT min_value FROM #{quoted_sequence}", "SCHEMA")
|
@@ -368,31 +368,6 @@ module ActiveRecord
|
|
368
368
|
SQL
|
369
369
|
end
|
370
370
|
|
371
|
-
def bulk_change_table(table_name, operations)
|
372
|
-
sql_fragments = []
|
373
|
-
non_combinable_operations = []
|
374
|
-
|
375
|
-
operations.each do |command, args|
|
376
|
-
table, arguments = args.shift, args
|
377
|
-
method = :"#{command}_for_alter"
|
378
|
-
|
379
|
-
if respond_to?(method, true)
|
380
|
-
sqls, procs = Array(send(method, table, *arguments)).partition { |v| v.is_a?(String) }
|
381
|
-
sql_fragments << sqls
|
382
|
-
non_combinable_operations.concat(procs)
|
383
|
-
else
|
384
|
-
execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
|
385
|
-
non_combinable_operations.each(&:call)
|
386
|
-
sql_fragments = []
|
387
|
-
non_combinable_operations = []
|
388
|
-
send(command, table, *arguments)
|
389
|
-
end
|
390
|
-
end
|
391
|
-
|
392
|
-
execute "ALTER TABLE #{quote_table_name(table_name)} #{sql_fragments.join(", ")}" unless sql_fragments.empty?
|
393
|
-
non_combinable_operations.each(&:call)
|
394
|
-
end
|
395
|
-
|
396
371
|
# Renames a table.
|
397
372
|
# Also renames a table's primary key sequence if the sequence name exists and
|
398
373
|
# matches the Active Record default.
|
@@ -443,14 +418,16 @@ module ActiveRecord
|
|
443
418
|
end
|
444
419
|
|
445
420
|
# Adds comment for given table column or drops it if +comment+ is a +nil+
|
446
|
-
def change_column_comment(table_name, column_name,
|
421
|
+
def change_column_comment(table_name, column_name, comment_or_changes) # :nodoc:
|
447
422
|
clear_cache!
|
423
|
+
comment = extract_new_comment_value(comment_or_changes)
|
448
424
|
execute "COMMENT ON COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column_name)} IS #{quote(comment)}"
|
449
425
|
end
|
450
426
|
|
451
427
|
# Adds comment for given table or drops it if +comment+ is a +nil+
|
452
|
-
def change_table_comment(table_name,
|
428
|
+
def change_table_comment(table_name, comment_or_changes) # :nodoc:
|
453
429
|
clear_cache!
|
430
|
+
comment = extract_new_comment_value(comment_or_changes)
|
454
431
|
execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS #{quote(comment)}"
|
455
432
|
end
|
456
433
|
|
@@ -548,21 +525,21 @@ module ActiveRecord
|
|
548
525
|
# The hard limit is 1GB, because of a 32-bit size field, and TOAST.
|
549
526
|
case limit
|
550
527
|
when nil, 0..0x3fffffff; super(type)
|
551
|
-
else raise
|
528
|
+
else raise ArgumentError, "No binary type has byte size #{limit}. The limit on binary can be at most 1GB - 1byte."
|
552
529
|
end
|
553
530
|
when "text"
|
554
531
|
# PostgreSQL doesn't support limits on text columns.
|
555
532
|
# The hard limit is 1GB, according to section 8.3 in the manual.
|
556
533
|
case limit
|
557
534
|
when nil, 0..0x3fffffff; super(type)
|
558
|
-
else raise
|
535
|
+
else raise ArgumentError, "No text type has byte size #{limit}. The limit on text can be at most 1GB - 1byte."
|
559
536
|
end
|
560
537
|
when "integer"
|
561
538
|
case limit
|
562
539
|
when 1, 2; "smallint"
|
563
540
|
when nil, 3, 4; "integer"
|
564
541
|
when 5..8; "bigint"
|
565
|
-
else raise
|
542
|
+
else raise ArgumentError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead."
|
566
543
|
end
|
567
544
|
else
|
568
545
|
super
|
@@ -623,10 +600,10 @@ module ActiveRecord
|
|
623
600
|
# validate_foreign_key :accounts, name: :special_fk_name
|
624
601
|
#
|
625
602
|
# The +options+ hash accepts the same keys as SchemaStatements#add_foreign_key.
|
626
|
-
def validate_foreign_key(from_table,
|
603
|
+
def validate_foreign_key(from_table, to_table = nil, **options)
|
627
604
|
return unless supports_validate_constraints?
|
628
605
|
|
629
|
-
fk_name_to_validate = foreign_key_for!(from_table,
|
606
|
+
fk_name_to_validate = foreign_key_for!(from_table, to_table: to_table, **options).name
|
630
607
|
|
631
608
|
validate_constraint from_table, fk_name_to_validate
|
632
609
|
end
|
@@ -650,16 +627,19 @@ module ActiveRecord
|
|
650
627
|
default_value = extract_value_from_default(default)
|
651
628
|
default_function = extract_default_function(default_value, default)
|
652
629
|
|
653
|
-
|
630
|
+
if match = default_function&.match(/\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z/)
|
631
|
+
serial = sequence_name_from_parts(table_name, column_name, match[:suffix]) == match[:sequence_name]
|
632
|
+
end
|
633
|
+
|
634
|
+
PostgreSQL::Column.new(
|
654
635
|
column_name,
|
655
636
|
default_value,
|
656
637
|
type_metadata,
|
657
638
|
!notnull,
|
658
|
-
table_name,
|
659
639
|
default_function,
|
660
|
-
collation,
|
640
|
+
collation: collation,
|
661
641
|
comment: comment.presence,
|
662
|
-
|
642
|
+
serial: serial
|
663
643
|
)
|
664
644
|
end
|
665
645
|
|
@@ -672,7 +652,23 @@ module ActiveRecord
|
|
672
652
|
precision: cast_type.precision,
|
673
653
|
scale: cast_type.scale,
|
674
654
|
)
|
675
|
-
|
655
|
+
PostgreSQL::TypeMetadata.new(simple_type, oid: oid, fmod: fmod)
|
656
|
+
end
|
657
|
+
|
658
|
+
def sequence_name_from_parts(table_name, column_name, suffix)
|
659
|
+
over_length = [table_name, column_name, suffix].sum(&:length) + 2 - max_identifier_length
|
660
|
+
|
661
|
+
if over_length > 0
|
662
|
+
column_name_length = [(max_identifier_length - suffix.length - 2) / 2, column_name.length].min
|
663
|
+
over_length -= column_name.length - column_name_length
|
664
|
+
column_name = column_name[0, column_name_length - [over_length, 0].min]
|
665
|
+
end
|
666
|
+
|
667
|
+
if over_length > 0
|
668
|
+
table_name = table_name[0, table_name.length - over_length]
|
669
|
+
end
|
670
|
+
|
671
|
+
"#{table_name}_#{column_name}_#{suffix}"
|
676
672
|
end
|
677
673
|
|
678
674
|
def extract_foreign_key_action(specifier)
|
@@ -3,38 +3,34 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
# :stopdoc:
|
5
5
|
module ConnectionAdapters
|
6
|
-
|
7
|
-
|
6
|
+
module PostgreSQL
|
7
|
+
class TypeMetadata < DelegateClass(SqlTypeMetadata)
|
8
|
+
undef to_yaml if method_defined?(:to_yaml)
|
8
9
|
|
9
|
-
|
10
|
+
attr_reader :oid, :fmod
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@array = /\[\]$/.match?(type_metadata.sql_type)
|
17
|
-
end
|
18
|
-
|
19
|
-
def sql_type
|
20
|
-
super.gsub(/\[\]$/, "")
|
21
|
-
end
|
22
|
-
|
23
|
-
def ==(other)
|
24
|
-
other.is_a?(PostgreSQLTypeMetadata) &&
|
25
|
-
attributes_for_hash == other.attributes_for_hash
|
26
|
-
end
|
27
|
-
alias eql? ==
|
28
|
-
|
29
|
-
def hash
|
30
|
-
attributes_for_hash.hash
|
31
|
-
end
|
12
|
+
def initialize(type_metadata, oid: nil, fmod: nil)
|
13
|
+
super(type_metadata)
|
14
|
+
@oid = oid
|
15
|
+
@fmod = fmod
|
16
|
+
end
|
32
17
|
|
33
|
-
|
18
|
+
def ==(other)
|
19
|
+
other.is_a?(TypeMetadata) &&
|
20
|
+
__getobj__ == other.__getobj__ &&
|
21
|
+
oid == other.oid &&
|
22
|
+
fmod == other.fmod
|
23
|
+
end
|
24
|
+
alias eql? ==
|
34
25
|
|
35
|
-
def
|
36
|
-
|
26
|
+
def hash
|
27
|
+
TypeMetadata.hash ^
|
28
|
+
__getobj__.hash ^
|
29
|
+
oid.hash ^
|
30
|
+
fmod.hash
|
37
31
|
end
|
32
|
+
end
|
38
33
|
end
|
34
|
+
PostgreSQLTypeMetadata = PostgreSQL::TypeMetadata
|
39
35
|
end
|
40
36
|
end
|
@@ -46,7 +46,7 @@ module ActiveRecord
|
|
46
46
|
conn = PG.connect(conn_params)
|
47
47
|
ConnectionAdapters::PostgreSQLAdapter.new(conn, logger, conn_params, config)
|
48
48
|
rescue ::PG::Error => error
|
49
|
-
if error.message.include?(
|
49
|
+
if error.message.include?(conn_params[:dbname])
|
50
50
|
raise ActiveRecord::NoDatabaseError
|
51
51
|
else
|
52
52
|
raise
|
@@ -196,6 +196,17 @@ module ActiveRecord
|
|
196
196
|
true
|
197
197
|
end
|
198
198
|
|
199
|
+
def supports_insert_returning?
|
200
|
+
true
|
201
|
+
end
|
202
|
+
|
203
|
+
def supports_insert_on_conflict?
|
204
|
+
database_version >= 90500
|
205
|
+
end
|
206
|
+
alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
|
207
|
+
alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
|
208
|
+
alias supports_insert_conflict_target? supports_insert_on_conflict?
|
209
|
+
|
199
210
|
def index_algorithms
|
200
211
|
{ concurrently: "CONCURRENTLY" }
|
201
212
|
end
|
@@ -236,15 +247,10 @@ module ActiveRecord
|
|
236
247
|
|
237
248
|
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
|
238
249
|
@local_tz = nil
|
239
|
-
@default_timezone = nil
|
240
|
-
@timestamp_decoder = nil
|
241
250
|
@max_identifier_length = nil
|
242
251
|
|
243
252
|
configure_connection
|
244
253
|
add_pg_encoders
|
245
|
-
@statements = StatementPool.new @connection,
|
246
|
-
self.class.type_cast_config_to_integer(config[:statement_limit])
|
247
|
-
|
248
254
|
add_pg_decoders
|
249
255
|
|
250
256
|
@type_map = Type::HashLookupTypeMap.new
|
@@ -253,15 +259,10 @@ module ActiveRecord
|
|
253
259
|
@use_insert_returning = @config.key?(:insert_returning) ? self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
|
254
260
|
end
|
255
261
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
end
|
261
|
-
end
|
262
|
-
|
263
|
-
def truncate(table_name, name = nil)
|
264
|
-
exec_query "TRUNCATE TABLE #{quote_table_name(table_name)}", name, []
|
262
|
+
def self.database_exists?(config)
|
263
|
+
!!ActiveRecord::Base.postgresql_connection(config)
|
264
|
+
rescue ActiveRecord::NoDatabaseError
|
265
|
+
false
|
265
266
|
end
|
266
267
|
|
267
268
|
# Is this connection alive and ready for queries?
|
@@ -280,6 +281,8 @@ module ActiveRecord
|
|
280
281
|
super
|
281
282
|
@connection.reset
|
282
283
|
configure_connection
|
284
|
+
rescue PG::ConnectionBad
|
285
|
+
connect
|
283
286
|
end
|
284
287
|
end
|
285
288
|
|
@@ -305,6 +308,7 @@ module ActiveRecord
|
|
305
308
|
end
|
306
309
|
|
307
310
|
def discard! # :nodoc:
|
311
|
+
super
|
308
312
|
@connection.socket_io.reopen(IO::NULL) rescue nil
|
309
313
|
@connection = nil
|
310
314
|
end
|
@@ -347,7 +351,18 @@ module ActiveRecord
|
|
347
351
|
end
|
348
352
|
|
349
353
|
def supports_pgcrypto_uuid?
|
350
|
-
|
354
|
+
database_version >= 90400
|
355
|
+
end
|
356
|
+
|
357
|
+
def supports_optimizer_hints?
|
358
|
+
unless defined?(@has_pg_hint_plan)
|
359
|
+
@has_pg_hint_plan = extension_available?("pg_hint_plan")
|
360
|
+
end
|
361
|
+
@has_pg_hint_plan
|
362
|
+
end
|
363
|
+
|
364
|
+
def supports_common_table_expressions?
|
365
|
+
true
|
351
366
|
end
|
352
367
|
|
353
368
|
def supports_lazy_transactions?
|
@@ -380,9 +395,12 @@ module ActiveRecord
|
|
380
395
|
}
|
381
396
|
end
|
382
397
|
|
398
|
+
def extension_available?(name)
|
399
|
+
query_value("SELECT true FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
|
400
|
+
end
|
401
|
+
|
383
402
|
def extension_enabled?(name)
|
384
|
-
|
385
|
-
res.cast_values.first
|
403
|
+
query_value("SELECT installed_version IS NOT NULL FROM pg_available_extensions WHERE name = #{quote(name)}", "SCHEMA")
|
386
404
|
end
|
387
405
|
|
388
406
|
def extensions
|
@@ -393,8 +411,6 @@ module ActiveRecord
|
|
393
411
|
def max_identifier_length
|
394
412
|
@max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
|
395
413
|
end
|
396
|
-
alias table_alias_length max_identifier_length
|
397
|
-
alias index_name_length max_identifier_length
|
398
414
|
|
399
415
|
# Set the authorized user for this session
|
400
416
|
def session_auth=(user)
|
@@ -417,20 +433,36 @@ module ActiveRecord
|
|
417
433
|
}
|
418
434
|
|
419
435
|
# Returns the version of the connected PostgreSQL server.
|
420
|
-
def
|
436
|
+
def get_database_version # :nodoc:
|
421
437
|
@connection.server_version
|
422
438
|
end
|
439
|
+
alias :postgresql_version :database_version
|
423
440
|
|
424
441
|
def default_index_type?(index) # :nodoc:
|
425
442
|
index.using == :btree || super
|
426
443
|
end
|
427
444
|
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
445
|
+
def build_insert_sql(insert) # :nodoc:
|
446
|
+
sql = +"INSERT #{insert.into} #{insert.values_list}"
|
447
|
+
|
448
|
+
if insert.skip_duplicates?
|
449
|
+
sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
|
450
|
+
elsif insert.update_duplicates?
|
451
|
+
sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
|
452
|
+
sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
|
453
|
+
end
|
454
|
+
|
455
|
+
sql << " RETURNING #{insert.returning}" if insert.returning
|
456
|
+
sql
|
457
|
+
end
|
458
|
+
|
459
|
+
def check_version # :nodoc:
|
460
|
+
if database_version < 90300
|
461
|
+
raise "Your version of PostgreSQL (#{database_version}) is too old. Active Record supports PostgreSQL >= 9.3."
|
433
462
|
end
|
463
|
+
end
|
464
|
+
|
465
|
+
private
|
434
466
|
|
435
467
|
# See https://www.postgresql.org/docs/current/static/errcodes-appendix.html
|
436
468
|
VALUE_LIMIT_VIOLATION = "22001"
|
@@ -723,6 +755,8 @@ module ActiveRecord
|
|
723
755
|
def connect
|
724
756
|
@connection = PG.connect(@connection_parameters)
|
725
757
|
configure_connection
|
758
|
+
add_pg_encoders
|
759
|
+
add_pg_decoders
|
726
760
|
end
|
727
761
|
|
728
762
|
# Configures the encoding, verbosity, schema search path, and time zone of the connection.
|
@@ -803,6 +837,10 @@ module ActiveRecord
|
|
803
837
|
Arel::Visitors::PostgreSQL.new(self)
|
804
838
|
end
|
805
839
|
|
840
|
+
def build_statement_pool
|
841
|
+
StatementPool.new(@connection, self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
842
|
+
end
|
843
|
+
|
806
844
|
def can_perform_case_insensitive_comparison_for?(column)
|
807
845
|
@case_insensitive_cache ||= {}
|
808
846
|
@case_insensitive_cache[column.sql_type] ||= begin
|
@@ -846,6 +884,9 @@ module ActiveRecord
|
|
846
884
|
end
|
847
885
|
|
848
886
|
def add_pg_decoders
|
887
|
+
@default_timezone = nil
|
888
|
+
@timestamp_decoder = nil
|
889
|
+
|
849
890
|
coders_by_name = {
|
850
891
|
"int2" => PG::TextDecoder::Integer,
|
851
892
|
"int4" => PG::TextDecoder::Integer,
|