activerecord 6.0.0.beta1 → 6.0.0

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.

Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +455 -9
  3. data/README.rdoc +3 -1
  4. data/lib/active_record/associations/association.rb +18 -1
  5. data/lib/active_record/associations/builder/association.rb +14 -18
  6. data/lib/active_record/associations/builder/belongs_to.rb +5 -2
  7. data/lib/active_record/associations/builder/collection_association.rb +5 -15
  8. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -1
  9. data/lib/active_record/associations/builder/has_many.rb +2 -0
  10. data/lib/active_record/associations/builder/has_one.rb +35 -1
  11. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  12. data/lib/active_record/associations/collection_association.rb +5 -6
  13. data/lib/active_record/associations/collection_proxy.rb +13 -42
  14. data/lib/active_record/associations/has_many_association.rb +1 -9
  15. data/lib/active_record/associations/has_many_through_association.rb +4 -11
  16. data/lib/active_record/associations/join_dependency/join_association.rb +21 -7
  17. data/lib/active_record/associations/join_dependency.rb +10 -9
  18. data/lib/active_record/associations/preloader/association.rb +37 -34
  19. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  20. data/lib/active_record/associations/preloader.rb +11 -6
  21. data/lib/active_record/associations.rb +3 -2
  22. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  23. data/lib/active_record/attribute_methods/dirty.rb +47 -14
  24. data/lib/active_record/attribute_methods/primary_key.rb +7 -15
  25. data/lib/active_record/attribute_methods/query.rb +2 -3
  26. data/lib/active_record/attribute_methods/read.rb +3 -9
  27. data/lib/active_record/attribute_methods/write.rb +6 -12
  28. data/lib/active_record/attribute_methods.rb +3 -53
  29. data/lib/active_record/attributes.rb +13 -0
  30. data/lib/active_record/autosave_association.rb +15 -5
  31. data/lib/active_record/base.rb +0 -1
  32. data/lib/active_record/callbacks.rb +3 -3
  33. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +124 -23
  34. data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
  35. data/lib/active_record/connection_adapters/abstract/database_statements.rb +101 -70
  36. data/lib/active_record/connection_adapters/abstract/query_cache.rb +11 -5
  37. data/lib/active_record/connection_adapters/abstract/quoting.rb +63 -6
  38. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -2
  39. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +51 -40
  40. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
  41. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +95 -30
  42. data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
  43. data/lib/active_record/connection_adapters/abstract_adapter.rb +108 -39
  44. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +93 -134
  45. data/lib/active_record/connection_adapters/column.rb +17 -13
  46. data/lib/active_record/connection_adapters/connection_specification.rb +1 -1
  47. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +3 -3
  48. data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -7
  49. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  50. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  51. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  52. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +66 -5
  53. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  54. data/lib/active_record/connection_adapters/mysql2_adapter.rb +18 -5
  55. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
  56. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +5 -1
  57. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  58. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  59. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
  60. data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -3
  61. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
  62. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +98 -89
  63. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +47 -63
  64. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
  65. data/lib/active_record/connection_adapters/postgresql_adapter.rb +91 -24
  66. data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
  67. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  68. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  69. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -2
  70. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +28 -2
  71. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +69 -118
  72. data/lib/active_record/connection_handling.rb +32 -16
  73. data/lib/active_record/core.rb +27 -20
  74. data/lib/active_record/database_configurations/hash_config.rb +11 -11
  75. data/lib/active_record/database_configurations/url_config.rb +21 -16
  76. data/lib/active_record/database_configurations.rb +99 -50
  77. data/lib/active_record/dynamic_matchers.rb +1 -1
  78. data/lib/active_record/enum.rb +15 -0
  79. data/lib/active_record/errors.rb +18 -13
  80. data/lib/active_record/fixtures.rb +11 -6
  81. data/lib/active_record/gem_version.rb +1 -1
  82. data/lib/active_record/inheritance.rb +1 -1
  83. data/lib/active_record/insert_all.rb +179 -0
  84. data/lib/active_record/integration.rb +13 -1
  85. data/lib/active_record/internal_metadata.rb +5 -1
  86. data/lib/active_record/locking/optimistic.rb +3 -4
  87. data/lib/active_record/log_subscriber.rb +1 -1
  88. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  89. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  90. data/lib/active_record/middleware/database_selector.rb +75 -0
  91. data/lib/active_record/migration/command_recorder.rb +28 -14
  92. data/lib/active_record/migration/compatibility.rb +72 -63
  93. data/lib/active_record/migration.rb +62 -44
  94. data/lib/active_record/persistence.rb +212 -19
  95. data/lib/active_record/querying.rb +18 -14
  96. data/lib/active_record/railtie.rb +9 -1
  97. data/lib/active_record/railties/collection_cache_association_loading.rb +3 -3
  98. data/lib/active_record/railties/databases.rake +124 -25
  99. data/lib/active_record/reflection.rb +18 -32
  100. data/lib/active_record/relation/calculations.rb +40 -44
  101. data/lib/active_record/relation/delegation.rb +23 -31
  102. data/lib/active_record/relation/finder_methods.rb +13 -13
  103. data/lib/active_record/relation/merger.rb +11 -16
  104. data/lib/active_record/relation/query_attribute.rb +5 -3
  105. data/lib/active_record/relation/query_methods.rb +217 -68
  106. data/lib/active_record/relation/spawn_methods.rb +1 -1
  107. data/lib/active_record/relation/where_clause.rb +10 -10
  108. data/lib/active_record/relation.rb +184 -35
  109. data/lib/active_record/sanitization.rb +33 -4
  110. data/lib/active_record/schema.rb +1 -1
  111. data/lib/active_record/schema_dumper.rb +10 -1
  112. data/lib/active_record/schema_migration.rb +1 -1
  113. data/lib/active_record/scoping/default.rb +7 -15
  114. data/lib/active_record/scoping/named.rb +10 -2
  115. data/lib/active_record/scoping.rb +6 -7
  116. data/lib/active_record/statement_cache.rb +2 -2
  117. data/lib/active_record/store.rb +48 -0
  118. data/lib/active_record/table_metadata.rb +9 -13
  119. data/lib/active_record/tasks/database_tasks.rb +109 -6
  120. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -1
  121. data/lib/active_record/test_databases.rb +1 -16
  122. data/lib/active_record/test_fixtures.rb +2 -2
  123. data/lib/active_record/timestamp.rb +35 -19
  124. data/lib/active_record/touch_later.rb +4 -2
  125. data/lib/active_record/transactions.rb +55 -45
  126. data/lib/active_record/type_caster/connection.rb +16 -10
  127. data/lib/active_record/validations/uniqueness.rb +4 -4
  128. data/lib/active_record/validations.rb +1 -0
  129. data/lib/active_record.rb +7 -1
  130. data/lib/arel/insert_manager.rb +3 -3
  131. data/lib/arel/nodes/and.rb +1 -1
  132. data/lib/arel/nodes/case.rb +1 -1
  133. data/lib/arel/nodes/comment.rb +29 -0
  134. data/lib/arel/nodes/select_core.rb +16 -12
  135. data/lib/arel/nodes/unary.rb +1 -0
  136. data/lib/arel/nodes/values_list.rb +2 -17
  137. data/lib/arel/nodes.rb +2 -1
  138. data/lib/arel/select_manager.rb +10 -10
  139. data/lib/arel/visitors/depth_first.rb +7 -2
  140. data/lib/arel/visitors/dot.rb +7 -2
  141. data/lib/arel/visitors/ibm_db.rb +13 -0
  142. data/lib/arel/visitors/informix.rb +6 -0
  143. data/lib/arel/visitors/mssql.rb +15 -1
  144. data/lib/arel/visitors/oracle12.rb +4 -5
  145. data/lib/arel/visitors/postgresql.rb +4 -10
  146. data/lib/arel/visitors/to_sql.rb +107 -131
  147. data/lib/arel/visitors/visitor.rb +9 -5
  148. data/lib/arel.rb +7 -0
  149. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
  150. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  151. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  152. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  153. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  154. metadata +17 -13
  155. data/lib/active_record/collection_cache_key.rb +0 -53
  156. data/lib/arel/nodes/values.rb +0 -16
@@ -110,7 +110,7 @@ module ActiveRecord
110
110
  end
111
111
  alias :exec_update :exec_delete
112
112
 
113
- def sql_for_insert(sql, pk, sequence_name, binds) # :nodoc:
113
+ def sql_for_insert(sql, pk, binds) # :nodoc:
114
114
  if pk.nil?
115
115
  # Extract the table from the insert sql. Yuck.
116
116
  table_ref = extract_table_ref_from_insert_sql(sql)
@@ -164,6 +164,10 @@ module ActiveRecord
164
164
  end
165
165
 
166
166
  private
167
+ def build_truncate_statements(*table_names)
168
+ "TRUNCATE TABLE #{table_names.map(&method(:quote_table_name)).join(", ")}"
169
+ end
170
+
167
171
  # Returns the current ID of a table's sequence.
168
172
  def last_insert_id_result(sequence_name)
169
173
  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+[\d,]+\.\d{2}$/ # (1)
29
+ when /^-?\D*[\d,]+\.\d{2}$/ # (1)
30
30
  value.gsub!(/[^-\d.]/, "")
31
- when /^-?\D+[\d.]+,\d{2}$/ # (2)
31
+ when /^-?\D*[\d.]+,\d{2}$/ # (2)
32
32
  value.gsub!(/[^-\d,]/, "").sub!(/,/, ".")
33
33
  end
34
34
 
@@ -64,7 +64,7 @@ module ActiveRecord
64
64
  end
65
65
 
66
66
  def type_cast_single_for_database(value)
67
- infinity?(value) ? value : @subtype.serialize(value)
67
+ infinity?(value) ? value : @subtype.serialize(@subtype.cast(value))
68
68
  end
69
69
 
70
70
  def extract_bounds(value)
@@ -13,9 +13,12 @@ module ActiveRecord
13
13
  :uuid
14
14
  end
15
15
 
16
- def cast(value)
17
- value.to_s[ACCEPTABLE_UUID, 0]
18
- end
16
+ private
17
+
18
+ def cast_value(value)
19
+ casted = value.to_s
20
+ casted if casted.match?(ACCEPTABLE_UUID)
21
+ end
19
22
  end
20
23
  end
21
24
  end
@@ -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
- @quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted.freeze
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
- @quoted_column_names[name] ||= PG::Connection.quote_ident(super).freeze
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)
@@ -138,7 +175,7 @@ module ActiveRecord
138
175
  end
139
176
 
140
177
  def encode_range(range)
141
- "[#{type_cast_range_value(range.first)},#{type_cast_range_value(range.last)}#{range.exclude_end? ? ')' : ']'}"
178
+ "[#{type_cast_range_value(range.begin)},#{type_cast_range_value(range.end)}#{range.exclude_end? ? ')' : ']'}"
142
179
  end
143
180
 
144
181
  def determine_encoding_of_strings_in_array(value)
@@ -17,6 +17,42 @@ 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}"
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
+
20
56
  def add_column_options!(sql, options)
21
57
  if options[:collation]
22
58
  sql << " COLLATE \"#{options[:collation]}\""
@@ -4,6 +4,8 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module PostgreSQL
6
6
  module ColumnMethods
7
+ extend ActiveSupport::Concern
8
+
7
9
  # Defines the primary key field.
8
10
  # Use of the native PostgreSQL UUID type is supported, and can be used
9
11
  # by defining your tables as such:
@@ -51,124 +53,131 @@ module ActiveRecord
51
53
  super
52
54
  end
53
55
 
54
- def bigserial(*args, **options)
55
- args.each { |name| column(name, :bigserial, options) }
56
- end
56
+ ##
57
+ # :method: bigserial
58
+ # :call-seq: bigserial(*names, **options)
57
59
 
58
- def bit(*args, **options)
59
- args.each { |name| column(name, :bit, options) }
60
- end
60
+ ##
61
+ # :method: bit
62
+ # :call-seq: bit(*names, **options)
61
63
 
62
- def bit_varying(*args, **options)
63
- args.each { |name| column(name, :bit_varying, options) }
64
- end
64
+ ##
65
+ # :method: bit_varying
66
+ # :call-seq: bit_varying(*names, **options)
65
67
 
66
- def cidr(*args, **options)
67
- args.each { |name| column(name, :cidr, options) }
68
- end
68
+ ##
69
+ # :method: cidr
70
+ # :call-seq: cidr(*names, **options)
69
71
 
70
- def citext(*args, **options)
71
- args.each { |name| column(name, :citext, options) }
72
- end
72
+ ##
73
+ # :method: citext
74
+ # :call-seq: citext(*names, **options)
73
75
 
74
- def daterange(*args, **options)
75
- args.each { |name| column(name, :daterange, options) }
76
- end
76
+ ##
77
+ # :method: daterange
78
+ # :call-seq: daterange(*names, **options)
77
79
 
78
- def hstore(*args, **options)
79
- args.each { |name| column(name, :hstore, options) }
80
- end
80
+ ##
81
+ # :method: hstore
82
+ # :call-seq: hstore(*names, **options)
81
83
 
82
- def inet(*args, **options)
83
- args.each { |name| column(name, :inet, options) }
84
- end
84
+ ##
85
+ # :method: inet
86
+ # :call-seq: inet(*names, **options)
85
87
 
86
- def interval(*args, **options)
87
- args.each { |name| column(name, :interval, options) }
88
- end
88
+ ##
89
+ # :method: interval
90
+ # :call-seq: interval(*names, **options)
89
91
 
90
- def int4range(*args, **options)
91
- args.each { |name| column(name, :int4range, options) }
92
- end
92
+ ##
93
+ # :method: int4range
94
+ # :call-seq: int4range(*names, **options)
93
95
 
94
- def int8range(*args, **options)
95
- args.each { |name| column(name, :int8range, options) }
96
- end
96
+ ##
97
+ # :method: int8range
98
+ # :call-seq: int8range(*names, **options)
97
99
 
98
- def jsonb(*args, **options)
99
- args.each { |name| column(name, :jsonb, options) }
100
- end
100
+ ##
101
+ # :method: jsonb
102
+ # :call-seq: jsonb(*names, **options)
101
103
 
102
- def ltree(*args, **options)
103
- args.each { |name| column(name, :ltree, options) }
104
- end
104
+ ##
105
+ # :method: ltree
106
+ # :call-seq: ltree(*names, **options)
105
107
 
106
- def macaddr(*args, **options)
107
- args.each { |name| column(name, :macaddr, options) }
108
- end
108
+ ##
109
+ # :method: macaddr
110
+ # :call-seq: macaddr(*names, **options)
109
111
 
110
- def money(*args, **options)
111
- args.each { |name| column(name, :money, options) }
112
- end
112
+ ##
113
+ # :method: money
114
+ # :call-seq: money(*names, **options)
113
115
 
114
- def numrange(*args, **options)
115
- args.each { |name| column(name, :numrange, options) }
116
- end
116
+ ##
117
+ # :method: numrange
118
+ # :call-seq: numrange(*names, **options)
117
119
 
118
- def oid(*args, **options)
119
- args.each { |name| column(name, :oid, options) }
120
- end
120
+ ##
121
+ # :method: oid
122
+ # :call-seq: oid(*names, **options)
121
123
 
122
- def point(*args, **options)
123
- args.each { |name| column(name, :point, options) }
124
- end
124
+ ##
125
+ # :method: point
126
+ # :call-seq: point(*names, **options)
125
127
 
126
- def line(*args, **options)
127
- args.each { |name| column(name, :line, options) }
128
- end
128
+ ##
129
+ # :method: line
130
+ # :call-seq: line(*names, **options)
129
131
 
130
- def lseg(*args, **options)
131
- args.each { |name| column(name, :lseg, options) }
132
- end
132
+ ##
133
+ # :method: lseg
134
+ # :call-seq: lseg(*names, **options)
133
135
 
134
- def box(*args, **options)
135
- args.each { |name| column(name, :box, options) }
136
- end
136
+ ##
137
+ # :method: box
138
+ # :call-seq: box(*names, **options)
137
139
 
138
- def path(*args, **options)
139
- args.each { |name| column(name, :path, options) }
140
- end
140
+ ##
141
+ # :method: path
142
+ # :call-seq: path(*names, **options)
141
143
 
142
- def polygon(*args, **options)
143
- args.each { |name| column(name, :polygon, options) }
144
- end
144
+ ##
145
+ # :method: polygon
146
+ # :call-seq: polygon(*names, **options)
145
147
 
146
- def circle(*args, **options)
147
- args.each { |name| column(name, :circle, options) }
148
- end
148
+ ##
149
+ # :method: circle
150
+ # :call-seq: circle(*names, **options)
149
151
 
150
- def serial(*args, **options)
151
- args.each { |name| column(name, :serial, options) }
152
- end
152
+ ##
153
+ # :method: serial
154
+ # :call-seq: serial(*names, **options)
153
155
 
154
- def tsrange(*args, **options)
155
- args.each { |name| column(name, :tsrange, options) }
156
- end
156
+ ##
157
+ # :method: tsrange
158
+ # :call-seq: tsrange(*names, **options)
157
159
 
158
- def tstzrange(*args, **options)
159
- args.each { |name| column(name, :tstzrange, options) }
160
- end
160
+ ##
161
+ # :method: tstzrange
162
+ # :call-seq: tstzrange(*names, **options)
161
163
 
162
- def tsvector(*args, **options)
163
- args.each { |name| column(name, :tsvector, options) }
164
- end
164
+ ##
165
+ # :method: tsvector
166
+ # :call-seq: tsvector(*names, **options)
165
167
 
166
- def uuid(*args, **options)
167
- args.each { |name| column(name, :uuid, options) }
168
- end
168
+ ##
169
+ # :method: uuid
170
+ # :call-seq: uuid(*names, **options)
171
+
172
+ ##
173
+ # :method: xml
174
+ # :call-seq: xml(*names, **options)
169
175
 
170
- def xml(*args, **options)
171
- args.each { |name| column(name, :xml, options) }
176
+ included do
177
+ define_column_methods :bigserial, :bit, :bit_varying, :cidr, :citext, :daterange,
178
+ :hstore, :inet, :interval, :int4range, :int8range, :jsonb, :ltree, :macaddr,
179
+ :money, :numrange, :oid, :point, :line, :lseg, :box, :path, :polygon, :circle,
180
+ :serial, :tsrange, :tstzrange, :tsvector, :uuid, :xml
172
181
  end
173
182
  end
174
183
 
@@ -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 postgresql_version >= 100000
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, comment) # :nodoc:
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, comment) # :nodoc:
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(ActiveRecordError, "No binary type has byte size #{limit}.")
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(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.")
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(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead.")
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, options_or_to_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, options_or_to_table).name
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
@@ -637,7 +614,7 @@ module ActiveRecord
637
614
  end
638
615
 
639
616
  def create_table_definition(*args)
640
- PostgreSQL::TableDefinition.new(*args)
617
+ PostgreSQL::TableDefinition.new(self, *args)
641
618
  end
642
619
 
643
620
  def create_alter_table(name)
@@ -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
- PostgreSQLColumn.new(
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
- max_identifier_length: max_identifier_length
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
- PostgreSQLTypeMetadata.new(simple_type, oid: oid, fmod: fmod)
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)
@@ -683,38 +679,20 @@ module ActiveRecord
683
679
  end
684
680
  end
685
681
 
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
-
703
682
  def add_column_for_alter(table_name, column_name, type, options = {})
704
683
  return super unless options.key?(:comment)
705
684
  [super, Proc.new { change_column_comment(table_name, column_name, options[:comment]) }]
706
685
  end
707
686
 
708
687
  def change_column_for_alter(table_name, column_name, type, options = {})
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)
688
+ td = create_table_definition(table_name)
689
+ cd = td.new_column_definition(column_name, type, options)
690
+ sqls = [schema_creation.accept(ChangeColumnDefinition.new(cd, column_name))]
712
691
  sqls << Proc.new { change_column_comment(table_name, column_name, options[:comment]) } if options.key?(:comment)
713
692
  sqls
714
693
  end
715
694
 
716
- # Changes the default value of a table column.
717
- def change_column_default_for_alter(table_name, column_name, default_or_changes) # :nodoc:
695
+ def change_column_default_for_alter(table_name, column_name, default_or_changes)
718
696
  column = column_for(table_name, column_name)
719
697
  return unless column
720
698
 
@@ -729,11 +707,17 @@ module ActiveRecord
729
707
  end
730
708
  end
731
709
 
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"
710
+ def change_column_null_for_alter(table_name, column_name, null, default = nil)
711
+ "ALTER COLUMN #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL"
734
712
  end
735
713
 
736
714
  def add_timestamps_for_alter(table_name, options = {})
715
+ options[:null] = false if options[:null].nil?
716
+
717
+ if !options.key?(:precision) && supports_datetime_with_precision?
718
+ options[:precision] = 6
719
+ end
720
+
737
721
  [add_column_for_alter(table_name, :created_at, :datetime, options), add_column_for_alter(table_name, :updated_at, :datetime, options)]
738
722
  end
739
723