activerecord 5.0.7.2 → 5.1.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.

Files changed (216) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +389 -2252
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/examples/performance.rb +28 -28
  6. data/examples/simple.rb +3 -3
  7. data/lib/active_record.rb +20 -20
  8. data/lib/active_record/aggregations.rb +244 -244
  9. data/lib/active_record/association_relation.rb +5 -5
  10. data/lib/active_record/associations.rb +1579 -1569
  11. data/lib/active_record/associations/alias_tracker.rb +1 -1
  12. data/lib/active_record/associations/association.rb +23 -15
  13. data/lib/active_record/associations/association_scope.rb +83 -81
  14. data/lib/active_record/associations/belongs_to_association.rb +0 -1
  15. data/lib/active_record/associations/builder/belongs_to.rb +16 -14
  16. data/lib/active_record/associations/builder/collection_association.rb +1 -2
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
  18. data/lib/active_record/associations/collection_association.rb +74 -241
  19. data/lib/active_record/associations/collection_proxy.rb +144 -70
  20. data/lib/active_record/associations/has_many_association.rb +15 -19
  21. data/lib/active_record/associations/has_many_through_association.rb +12 -5
  22. data/lib/active_record/associations/has_one_association.rb +22 -28
  23. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  24. data/lib/active_record/associations/join_dependency.rb +117 -115
  25. data/lib/active_record/associations/join_dependency/join_association.rb +16 -13
  26. data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
  27. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  28. data/lib/active_record/associations/preloader.rb +94 -94
  29. data/lib/active_record/associations/preloader/association.rb +87 -64
  30. data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
  31. data/lib/active_record/associations/preloader/collection_association.rb +6 -6
  32. data/lib/active_record/associations/preloader/has_many.rb +0 -2
  33. data/lib/active_record/associations/preloader/singular_association.rb +6 -8
  34. data/lib/active_record/associations/preloader/through_association.rb +34 -41
  35. data/lib/active_record/associations/singular_association.rb +8 -25
  36. data/lib/active_record/associations/through_association.rb +3 -6
  37. data/lib/active_record/attribute.rb +98 -71
  38. data/lib/active_record/attribute/user_provided_default.rb +4 -2
  39. data/lib/active_record/attribute_assignment.rb +61 -61
  40. data/lib/active_record/attribute_decorators.rb +35 -13
  41. data/lib/active_record/attribute_methods.rb +56 -65
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
  43. data/lib/active_record/attribute_methods/dirty.rb +216 -34
  44. data/lib/active_record/attribute_methods/primary_key.rb +78 -73
  45. data/lib/active_record/attribute_methods/read.rb +39 -35
  46. data/lib/active_record/attribute_methods/serialization.rb +7 -7
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
  48. data/lib/active_record/attribute_methods/write.rb +36 -30
  49. data/lib/active_record/attribute_mutation_tracker.rb +53 -10
  50. data/lib/active_record/attribute_set.rb +9 -6
  51. data/lib/active_record/attribute_set/builder.rb +41 -49
  52. data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
  53. data/lib/active_record/attributes.rb +21 -21
  54. data/lib/active_record/autosave_association.rb +13 -13
  55. data/lib/active_record/base.rb +24 -22
  56. data/lib/active_record/callbacks.rb +52 -14
  57. data/lib/active_record/coders/yaml_column.rb +9 -11
  58. data/lib/active_record/collection_cache_key.rb +6 -17
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +320 -278
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -34
  62. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -27
  63. data/lib/active_record/connection_adapters/abstract/quoting.rb +44 -57
  64. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +9 -19
  65. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +78 -79
  66. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
  67. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +99 -93
  68. data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -5
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +156 -128
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +424 -382
  71. data/lib/active_record/connection_adapters/column.rb +27 -5
  72. data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
  73. data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -43
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +49 -31
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +5 -6
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +24 -26
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +1 -28
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -35
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +9 -9
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  91. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
  92. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
  93. data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
  94. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  95. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
  97. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +28 -30
  98. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
  100. data/lib/active_record/connection_adapters/postgresql/quoting.rb +38 -36
  101. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
  102. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
  103. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
  104. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +161 -170
  105. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +4 -4
  106. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -7
  107. data/lib/active_record/connection_adapters/postgresql_adapter.rb +179 -152
  108. data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
  109. data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
  110. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
  111. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -20
  112. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
  113. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
  114. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +187 -130
  116. data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
  117. data/lib/active_record/connection_handling.rb +14 -26
  118. data/lib/active_record/core.rb +110 -93
  119. data/lib/active_record/counter_cache.rb +62 -13
  120. data/lib/active_record/define_callbacks.rb +20 -0
  121. data/lib/active_record/dynamic_matchers.rb +80 -79
  122. data/lib/active_record/enum.rb +8 -6
  123. data/lib/active_record/errors.rb +58 -15
  124. data/lib/active_record/explain.rb +1 -2
  125. data/lib/active_record/explain_registry.rb +1 -1
  126. data/lib/active_record/explain_subscriber.rb +7 -4
  127. data/lib/active_record/fixture_set/file.rb +11 -8
  128. data/lib/active_record/fixtures.rb +66 -53
  129. data/lib/active_record/gem_version.rb +3 -3
  130. data/lib/active_record/inheritance.rb +93 -79
  131. data/lib/active_record/integration.rb +7 -7
  132. data/lib/active_record/internal_metadata.rb +3 -16
  133. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  134. data/lib/active_record/locking/optimistic.rb +64 -56
  135. data/lib/active_record/locking/pessimistic.rb +10 -1
  136. data/lib/active_record/log_subscriber.rb +29 -29
  137. data/lib/active_record/migration.rb +155 -172
  138. data/lib/active_record/migration/command_recorder.rb +94 -94
  139. data/lib/active_record/migration/compatibility.rb +76 -37
  140. data/lib/active_record/migration/join_table.rb +6 -6
  141. data/lib/active_record/model_schema.rb +85 -119
  142. data/lib/active_record/nested_attributes.rb +200 -199
  143. data/lib/active_record/null_relation.rb +10 -33
  144. data/lib/active_record/persistence.rb +45 -38
  145. data/lib/active_record/query_cache.rb +4 -8
  146. data/lib/active_record/querying.rb +2 -3
  147. data/lib/active_record/railtie.rb +16 -17
  148. data/lib/active_record/railties/controller_runtime.rb +6 -2
  149. data/lib/active_record/railties/databases.rake +125 -140
  150. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  151. data/lib/active_record/readonly_attributes.rb +2 -2
  152. data/lib/active_record/reflection.rb +79 -96
  153. data/lib/active_record/relation.rb +72 -115
  154. data/lib/active_record/relation/batches.rb +87 -58
  155. data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
  156. data/lib/active_record/relation/calculations.rb +154 -160
  157. data/lib/active_record/relation/delegation.rb +30 -29
  158. data/lib/active_record/relation/finder_methods.rb +195 -226
  159. data/lib/active_record/relation/merger.rb +58 -62
  160. data/lib/active_record/relation/predicate_builder.rb +92 -89
  161. data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
  162. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
  163. data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
  164. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
  165. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
  166. data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
  167. data/lib/active_record/relation/query_attribute.rb +1 -1
  168. data/lib/active_record/relation/query_methods.rb +247 -295
  169. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  170. data/lib/active_record/relation/spawn_methods.rb +4 -5
  171. data/lib/active_record/relation/where_clause.rb +79 -65
  172. data/lib/active_record/relation/where_clause_factory.rb +47 -8
  173. data/lib/active_record/result.rb +29 -31
  174. data/lib/active_record/runtime_registry.rb +3 -3
  175. data/lib/active_record/sanitization.rb +182 -197
  176. data/lib/active_record/schema.rb +3 -3
  177. data/lib/active_record/schema_dumper.rb +14 -37
  178. data/lib/active_record/schema_migration.rb +3 -3
  179. data/lib/active_record/scoping.rb +9 -10
  180. data/lib/active_record/scoping/default.rb +87 -91
  181. data/lib/active_record/scoping/named.rb +16 -28
  182. data/lib/active_record/secure_token.rb +2 -2
  183. data/lib/active_record/statement_cache.rb +13 -15
  184. data/lib/active_record/store.rb +31 -32
  185. data/lib/active_record/suppressor.rb +2 -1
  186. data/lib/active_record/table_metadata.rb +9 -5
  187. data/lib/active_record/tasks/database_tasks.rb +72 -65
  188. data/lib/active_record/tasks/mysql_database_tasks.rb +75 -72
  189. data/lib/active_record/tasks/postgresql_database_tasks.rb +53 -48
  190. data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
  191. data/lib/active_record/timestamp.rb +39 -25
  192. data/lib/active_record/touch_later.rb +1 -2
  193. data/lib/active_record/transactions.rb +98 -110
  194. data/lib/active_record/type.rb +17 -13
  195. data/lib/active_record/type/adapter_specific_registry.rb +46 -42
  196. data/lib/active_record/type/decimal_without_scale.rb +9 -0
  197. data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
  198. data/lib/active_record/type/serialized.rb +8 -8
  199. data/lib/active_record/type/text.rb +9 -0
  200. data/lib/active_record/type/time.rb +0 -1
  201. data/lib/active_record/type/type_map.rb +11 -15
  202. data/lib/active_record/type/unsigned_integer.rb +15 -0
  203. data/lib/active_record/type_caster.rb +2 -2
  204. data/lib/active_record/type_caster/connection.rb +8 -6
  205. data/lib/active_record/type_caster/map.rb +3 -1
  206. data/lib/active_record/validations.rb +4 -4
  207. data/lib/active_record/validations/associated.rb +1 -1
  208. data/lib/active_record/validations/presence.rb +2 -2
  209. data/lib/active_record/validations/uniqueness.rb +8 -39
  210. data/lib/active_record/version.rb +1 -1
  211. data/lib/rails/generators/active_record.rb +4 -4
  212. data/lib/rails/generators/active_record/migration.rb +2 -2
  213. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
  214. data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
  215. metadata +22 -13
  216. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -11,11 +11,22 @@ module ActiveRecord
11
11
  # t.timestamps
12
12
  # end
13
13
  #
14
- # By default, this will use the +uuid_generate_v4()+ function from the
15
- # +uuid-ossp+ extension, which MUST be enabled on your database. To enable
16
- # the +uuid-ossp+ extension, you can use the +enable_extension+ method in your
17
- # migrations. To use a UUID primary key without +uuid-ossp+ enabled, you can
18
- # set the +:default+ option to +nil+:
14
+ # By default, this will use the +gen_random_uuid()+ function from the
15
+ # +pgcrypto+ extension. As that extension is only available in
16
+ # PostgreSQL 9.4+, for earlier versions an explicit default can be set
17
+ # to use +uuid_generate_v4()+ from the +uuid-ossp+ extension instead:
18
+ #
19
+ # create_table :stuffs, id: false do |t|
20
+ # t.primary_key :id, :uuid, default: "uuid_generate_v4()"
21
+ # t.uuid :foo_id
22
+ # t.timestamps
23
+ # end
24
+ #
25
+ # To enable the appropriate extension, which is a requirement, use
26
+ # the +enable_extension+ method in your migrations.
27
+ #
28
+ # To use a UUID primary key without any of the extensions, set the
29
+ # +:default+ option to +nil+:
19
30
  #
20
31
  # create_table :stuffs, id: false do |t|
21
32
  # t.primary_key :id, :uuid, default: nil
@@ -23,15 +34,25 @@ module ActiveRecord
23
34
  # t.timestamps
24
35
  # end
25
36
  #
26
- # You may also pass a different UUID generation function from +uuid-ossp+
27
- # or another library.
37
+ # You may also pass a custom stored procedure that returns a UUID or use a
38
+ # different UUID generation function from another library.
28
39
  #
29
40
  # Note that setting the UUID primary key default value to +nil+ will
30
41
  # require you to assure that you always provide a UUID value before saving
31
42
  # a record (as primary keys cannot be +nil+). This might be done via the
32
43
  # +SecureRandom.uuid+ method and a +before_save+ callback, for instance.
33
44
  def primary_key(name, type = :primary_key, **options)
34
- options[:default] = options.fetch(:default, 'uuid_generate_v4()') if type == :uuid
45
+ options[:auto_increment] = true if [:integer, :bigint].include?(type) && !options.key?(:default)
46
+ if type == :uuid
47
+ options[:default] = options.fetch(:default, "gen_random_uuid()")
48
+ elsif options.delete(:auto_increment) == true && %i(integer bigint).include?(type)
49
+ type = if type == :bigint || options[:limit] == 8
50
+ :bigserial
51
+ else
52
+ :serial
53
+ end
54
+ end
55
+
35
56
  super
36
57
  end
37
58
 
@@ -67,6 +88,10 @@ module ActiveRecord
67
88
  args.each { |name| column(name, :inet, options) }
68
89
  end
69
90
 
91
+ def interval(*args, **options)
92
+ args.each { |name| column(name, :interval, options) }
93
+ end
94
+
70
95
  def int4range(*args, **options)
71
96
  args.each { |name| column(name, :int4range, options) }
72
97
  end
@@ -99,6 +124,10 @@ module ActiveRecord
99
124
  args.each { |name| column(name, :numrange, options) }
100
125
  end
101
126
 
127
+ def oid(*args, **options)
128
+ args.each { |name| column(name, :oid, options) }
129
+ end
130
+
102
131
  def point(*args, **options)
103
132
  args.each { |name| column(name, :point, options) }
104
133
  end
@@ -152,24 +181,8 @@ module ActiveRecord
152
181
  end
153
182
  end
154
183
 
155
- class ColumnDefinition < ActiveRecord::ConnectionAdapters::ColumnDefinition
156
- attr_accessor :array
157
- end
158
-
159
184
  class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
160
185
  include ColumnMethods
161
-
162
- def new_column_definition(name, type, options) # :nodoc:
163
- column = super
164
- column.array = options[:array]
165
- column
166
- end
167
-
168
- private
169
-
170
- def create_column_definition(name, type)
171
- PostgreSQL::ColumnDefinition.new name, type
172
- end
173
186
  end
174
187
 
175
188
  class Table < ActiveRecord::ConnectionAdapters::Table
@@ -1,19 +1,11 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module PostgreSQL
4
- module ColumnDumper
5
- def column_spec_for_primary_key(column)
6
- spec = super
7
- if schema_type(column) == :uuid
8
- spec[:default] ||= 'nil'
9
- end
10
- spec
11
- end
12
-
4
+ module ColumnDumper # :nodoc:
13
5
  # Adds +:array+ option to the default set
14
6
  def prepare_column_options(column)
15
7
  spec = super
16
- spec[:array] = 'true' if column.array?
8
+ spec[:array] = "true" if column.array?
17
9
  spec
18
10
  end
19
11
 
@@ -24,23 +16,27 @@ module ActiveRecord
24
16
 
25
17
  private
26
18
 
27
- def default_primary_key?(column)
28
- schema_type(column) == :serial
29
- end
19
+ def default_primary_key?(column)
20
+ schema_type(column) == :bigserial
21
+ end
22
+
23
+ def explicit_primary_key_default?(column)
24
+ column.type == :uuid || (column.type == :integer && !column.serial?)
25
+ end
30
26
 
31
- def schema_type(column)
32
- return super unless column.serial?
27
+ def schema_type(column)
28
+ return super unless column.serial?
33
29
 
34
- if column.bigint?
35
- :bigserial
36
- else
37
- :serial
30
+ if column.bigint?
31
+ :bigserial
32
+ else
33
+ :serial
34
+ end
38
35
  end
39
- end
40
36
 
41
- def schema_expression(column)
42
- super unless column.serial?
43
- end
37
+ def schema_expression(column)
38
+ super unless column.serial?
39
+ end
44
40
  end
45
41
  end
46
42
  end
@@ -1,24 +1,8 @@
1
- require 'active_support/core_ext/string/strip'
1
+ require "active_support/core_ext/string/strip"
2
2
 
3
3
  module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module PostgreSQL
6
- class SchemaCreation < AbstractAdapter::SchemaCreation
7
- private
8
-
9
- def visit_ColumnDefinition(o)
10
- o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale, o.array)
11
- super
12
- end
13
-
14
- def add_column_options!(sql, options)
15
- if options[:collation]
16
- sql << " COLLATE \"#{options[:collation]}\""
17
- end
18
- super
19
- end
20
- end
21
-
22
6
  module SchemaStatements
23
7
  # Drops the database specified on the +name+ attribute
24
8
  # and creates it again using the provided +options+.
@@ -36,26 +20,26 @@ module ActiveRecord
36
20
  # create_database config[:database], config
37
21
  # create_database 'foo_development', encoding: 'unicode'
38
22
  def create_database(name, options = {})
39
- options = { encoding: 'utf8' }.merge!(options.symbolize_keys)
23
+ options = { encoding: "utf8" }.merge!(options.symbolize_keys)
40
24
 
41
25
  option_string = options.inject("") do |memo, (key, value)|
42
26
  memo += case key
43
- when :owner
44
- " OWNER = \"#{value}\""
45
- when :template
46
- " TEMPLATE = \"#{value}\""
47
- when :encoding
48
- " ENCODING = '#{value}'"
49
- when :collation
50
- " LC_COLLATE = '#{value}'"
51
- when :ctype
52
- " LC_CTYPE = '#{value}'"
53
- when :tablespace
54
- " TABLESPACE = \"#{value}\""
55
- when :connection_limit
56
- " CONNECTION LIMIT = #{value}"
27
+ when :owner
28
+ " OWNER = \"#{value}\""
29
+ when :template
30
+ " TEMPLATE = \"#{value}\""
31
+ when :encoding
32
+ " ENCODING = '#{value}'"
33
+ when :collation
34
+ " LC_COLLATE = '#{value}'"
35
+ when :ctype
36
+ " LC_CTYPE = '#{value}'"
37
+ when :tablespace
38
+ " TABLESPACE = \"#{value}\""
39
+ when :connection_limit
40
+ " CONNECTION LIMIT = #{value}"
57
41
  else
58
- ""
42
+ ""
59
43
  end
60
44
  end
61
45
 
@@ -71,22 +55,26 @@ module ActiveRecord
71
55
  end
72
56
 
73
57
  # Returns the list of all tables in the schema search path.
74
- def tables(name = nil)
75
- if name
76
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
77
- Passing arguments to #tables is deprecated without replacement.
78
- MSG
79
- end
80
-
81
- select_values("SELECT tablename FROM pg_tables WHERE schemaname = ANY(current_schemas(false))", 'SCHEMA')
58
+ def tables
59
+ select_values("SELECT tablename FROM pg_tables WHERE schemaname = ANY(current_schemas(false))", "SCHEMA")
82
60
  end
83
61
 
84
62
  def data_sources # :nodoc
85
- select_values(<<-SQL, 'SCHEMA')
63
+ select_values(<<-SQL, "SCHEMA")
86
64
  SELECT c.relname
87
65
  FROM pg_class c
88
66
  LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
89
- WHERE c.relkind IN ('r', 'v','m') -- (r)elation/table, (v)iew, (m)aterialized view
67
+ WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view
68
+ AND n.nspname = ANY (current_schemas(false))
69
+ SQL
70
+ end
71
+
72
+ def views # :nodoc:
73
+ select_values(<<-SQL, "SCHEMA")
74
+ SELECT c.relname
75
+ FROM pg_class c
76
+ LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
77
+ WHERE c.relkind IN ('v','m') -- (v)iew, (m)aterialized view
90
78
  AND n.nspname = ANY (current_schemas(false))
91
79
  SQL
92
80
  end
@@ -95,36 +83,28 @@ module ActiveRecord
95
83
  # If the schema is not specified as part of +name+ then it will only find tables within
96
84
  # the current schema search path (regardless of permissions to access tables in other schemas)
97
85
  def table_exists?(name)
98
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
99
- #table_exists? currently checks both tables and views.
100
- This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
101
- Use #data_source_exists? instead.
102
- MSG
103
-
104
- data_source_exists?(name)
105
- end
106
-
107
- def data_source_exists?(name)
108
86
  name = Utils.extract_schema_qualified_name(name.to_s)
109
87
  return false unless name.identifier
110
88
 
111
- select_value(<<-SQL, 'SCHEMA').to_i > 0
112
- SELECT COUNT(*)
113
- FROM pg_class c
114
- LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
115
- WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view
116
- AND c.relname = '#{name.identifier}'
117
- AND n.nspname = #{name.schema ? "'#{name.schema}'" : 'ANY (current_schemas(false))'}
89
+ select_values(<<-SQL, "SCHEMA").any?
90
+ SELECT tablename
91
+ FROM pg_tables
92
+ WHERE tablename = #{quote(name.identifier)}
93
+ AND schemaname = #{name.schema ? quote(name.schema) : "ANY (current_schemas(false))"}
118
94
  SQL
119
95
  end
120
96
 
121
- def views # :nodoc:
122
- select_values(<<-SQL, 'SCHEMA')
97
+ def data_source_exists?(name) # :nodoc:
98
+ name = Utils.extract_schema_qualified_name(name.to_s)
99
+ return false unless name.identifier
100
+
101
+ select_values(<<-SQL, "SCHEMA").any?
123
102
  SELECT c.relname
124
103
  FROM pg_class c
125
104
  LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
126
- WHERE c.relkind IN ('v','m') -- (v)iew, (m)aterialized view
127
- AND n.nspname = ANY (current_schemas(false))
105
+ WHERE c.relkind IN ('r','v','m') -- (r)elation/table, (v)iew, (m)aterialized view
106
+ AND c.relname = #{quote(name.identifier)}
107
+ AND n.nspname = #{name.schema ? quote(name.schema) : "ANY (current_schemas(false))"}
128
108
  SQL
129
109
  end
130
110
 
@@ -132,13 +112,13 @@ module ActiveRecord
132
112
  name = Utils.extract_schema_qualified_name(view_name.to_s)
133
113
  return false unless name.identifier
134
114
 
135
- select_values(<<-SQL, 'SCHEMA').any?
115
+ select_values(<<-SQL, "SCHEMA").any?
136
116
  SELECT c.relname
137
117
  FROM pg_class c
138
118
  LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
139
119
  WHERE c.relkind IN ('v','m') -- (v)iew, (m)aterialized view
140
- AND c.relname = '#{name.identifier}'
141
- AND n.nspname = #{name.schema ? "'#{name.schema}'" : 'ANY (current_schemas(false))'}
120
+ AND c.relname = #{quote(name.identifier)}
121
+ AND n.nspname = #{name.schema ? quote(name.schema) : "ANY (current_schemas(false))"}
142
122
  SQL
143
123
  end
144
124
 
@@ -148,15 +128,20 @@ module ActiveRecord
148
128
 
149
129
  # Returns true if schema exists.
150
130
  def schema_exists?(name)
151
- select_value("SELECT COUNT(*) FROM pg_namespace WHERE nspname = '#{name}'", 'SCHEMA').to_i > 0
131
+ select_value("SELECT COUNT(*) FROM pg_namespace WHERE nspname = '#{name}'", "SCHEMA").to_i > 0
152
132
  end
153
133
 
154
134
  # Verifies existence of an index with a given name.
155
- def index_name_exists?(table_name, index_name, default)
135
+ def index_name_exists?(table_name, index_name, default = nil)
136
+ unless default.nil?
137
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
138
+ Passing default to #index_name_exists? is deprecated without replacement.
139
+ MSG
140
+ end
156
141
  table = Utils.extract_schema_qualified_name(table_name.to_s)
157
142
  index = Utils.extract_schema_qualified_name(index_name.to_s)
158
143
 
159
- select_value(<<-SQL, 'SCHEMA').to_i > 0
144
+ select_value(<<-SQL, "SCHEMA").to_i > 0
160
145
  SELECT COUNT(*)
161
146
  FROM pg_class t
162
147
  INNER JOIN pg_index d ON t.oid = d.indrelid
@@ -170,10 +155,16 @@ module ActiveRecord
170
155
  end
171
156
 
172
157
  # Returns an array of indexes for the given table.
173
- def indexes(table_name, name = nil)
158
+ def indexes(table_name, name = nil) # :nodoc:
159
+ if name
160
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
161
+ Passing name to #indexes is deprecated without replacement.
162
+ MSG
163
+ end
164
+
174
165
  table = Utils.extract_schema_qualified_name(table_name.to_s)
175
166
 
176
- result = query(<<-SQL, 'SCHEMA')
167
+ result = query(<<-SQL, "SCHEMA")
177
168
  SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid,
178
169
  pg_catalog.obj_description(i.oid, 'pg_class') AS comment,
179
170
  (SELECT COUNT(*) FROM pg_opclass o
@@ -221,21 +212,23 @@ module ActiveRecord
221
212
  end.compact
222
213
  end
223
214
 
224
- # Returns the list of all column definitions for a table.
225
- def columns(table_name) # :nodoc:
226
- table_name = table_name.to_s
227
- column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod, collation, comment|
228
- oid = oid.to_i
229
- fmod = fmod.to_i
230
- type_metadata = fetch_type_metadata(column_name, type, oid, fmod)
231
- default_value = extract_value_from_default(default)
232
- default_function = extract_default_function(default_value, default)
233
- new_column(column_name, default_value, type_metadata, !notnull, table_name, default_function, collation, comment: comment.presence, max_identifier_length: max_identifier_length)
234
- end
235
- end
236
-
237
- def new_column(*args) # :nodoc:
238
- PostgreSQLColumn.new(*args)
215
+ def new_column_from_field(table_name, field) # :nondoc:
216
+ column_name, type, default, notnull, oid, fmod, collation, comment = field
217
+ oid = oid.to_i
218
+ fmod = fmod.to_i
219
+ type_metadata = fetch_type_metadata(column_name, type, oid, fmod)
220
+ default_value = extract_value_from_default(default)
221
+ default_function = extract_default_function(default_value, default)
222
+ PostgreSQLColumn.new(
223
+ column_name,
224
+ default_value,
225
+ type_metadata,
226
+ !notnull,
227
+ table_name,
228
+ default_function,
229
+ collation,
230
+ comment: comment.presence
231
+ )
239
232
  end
240
233
 
241
234
  def table_options(table_name) # :nodoc:
@@ -248,7 +241,7 @@ module ActiveRecord
248
241
  def table_comment(table_name) # :nodoc:
249
242
  name = Utils.extract_schema_qualified_name(table_name.to_s)
250
243
  if name.identifier
251
- select_value(<<-SQL.strip_heredoc, 'SCHEMA')
244
+ select_value(<<-SQL.strip_heredoc, "SCHEMA")
252
245
  SELECT pg_catalog.obj_description(c.oid, 'pg_class')
253
246
  FROM pg_catalog.pg_class c
254
247
  LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
@@ -261,32 +254,32 @@ module ActiveRecord
261
254
 
262
255
  # Returns the current database name.
263
256
  def current_database
264
- select_value('select current_database()', 'SCHEMA')
257
+ select_value("select current_database()", "SCHEMA")
265
258
  end
266
259
 
267
260
  # Returns the current schema name.
268
261
  def current_schema
269
- select_value('SELECT current_schema', 'SCHEMA')
262
+ select_value("SELECT current_schema", "SCHEMA")
270
263
  end
271
264
 
272
265
  # Returns the current database encoding format.
273
266
  def encoding
274
- select_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA')
267
+ select_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname LIKE '#{current_database}'", "SCHEMA")
275
268
  end
276
269
 
277
270
  # Returns the current database collation.
278
271
  def collation
279
- select_value("SELECT datcollate FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA')
272
+ select_value("SELECT datcollate FROM pg_database WHERE datname LIKE '#{current_database}'", "SCHEMA")
280
273
  end
281
274
 
282
275
  # Returns the current database ctype.
283
276
  def ctype
284
- select_value("SELECT datctype FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA')
277
+ select_value("SELECT datctype FROM pg_database WHERE datname LIKE '#{current_database}'", "SCHEMA")
285
278
  end
286
279
 
287
280
  # Returns an array of schema names.
288
281
  def schema_names
289
- select_values(<<-SQL, 'SCHEMA')
282
+ select_values(<<-SQL, "SCHEMA")
290
283
  SELECT nspname
291
284
  FROM pg_namespace
292
285
  WHERE nspname !~ '^pg_.*'
@@ -296,7 +289,7 @@ module ActiveRecord
296
289
  end
297
290
 
298
291
  # Creates a schema for the given schema name.
299
- def create_schema schema_name
292
+ def create_schema(schema_name)
300
293
  execute "CREATE SCHEMA #{quote_schema_name(schema_name)}"
301
294
  end
302
295
 
@@ -312,37 +305,37 @@ module ActiveRecord
312
305
  # This should be not be called manually but set in database.yml.
313
306
  def schema_search_path=(schema_csv)
314
307
  if schema_csv
315
- execute("SET search_path TO #{schema_csv}", 'SCHEMA')
308
+ execute("SET search_path TO #{schema_csv}", "SCHEMA")
316
309
  @schema_search_path = schema_csv
317
310
  end
318
311
  end
319
312
 
320
313
  # Returns the active schema search path.
321
314
  def schema_search_path
322
- @schema_search_path ||= select_value('SHOW search_path', 'SCHEMA')
315
+ @schema_search_path ||= select_value("SHOW search_path", "SCHEMA")
323
316
  end
324
317
 
325
318
  # Returns the current client message level.
326
319
  def client_min_messages
327
- select_value('SHOW client_min_messages', 'SCHEMA')
320
+ select_value("SHOW client_min_messages", "SCHEMA")
328
321
  end
329
322
 
330
323
  # Set the client message level.
331
324
  def client_min_messages=(level)
332
- execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
325
+ execute("SET client_min_messages TO '#{level}'", "SCHEMA")
333
326
  end
334
327
 
335
328
  # Returns the sequence name for a table's primary key or some other specified key.
336
- def default_sequence_name(table_name, pk = nil) #:nodoc:
337
- result = serial_sequence(table_name, pk || 'id')
329
+ def default_sequence_name(table_name, pk = "id") #:nodoc:
330
+ result = serial_sequence(table_name, pk)
338
331
  return nil unless result
339
332
  Utils.extract_schema_qualified_name(result).to_s
340
333
  rescue ActiveRecord::StatementInvalid
341
- PostgreSQL::Name.new(nil, "#{table_name}_#{pk || 'id'}_seq").to_s
334
+ PostgreSQL::Name.new(nil, "#{table_name}_#{pk}_seq").to_s
342
335
  end
343
336
 
344
337
  def serial_sequence(table, column)
345
- select_value("SELECT pg_get_serial_sequence('#{table}', '#{column}')", 'SCHEMA')
338
+ select_value("SELECT pg_get_serial_sequence('#{table}', '#{column}')", "SCHEMA")
346
339
  end
347
340
 
348
341
  # Sets the sequence of a table's primary key to the specified value.
@@ -353,7 +346,7 @@ module ActiveRecord
353
346
  if sequence
354
347
  quoted_sequence = quote_table_name(sequence)
355
348
 
356
- select_value("SELECT setval('#{quoted_sequence}', #{value})", 'SCHEMA')
349
+ select_value("SELECT setval('#{quoted_sequence}', #{value})", "SCHEMA")
357
350
  else
358
351
  @logger.warn "#{table} has primary key #{pk} with no default sequence." if @logger
359
352
  end
@@ -362,7 +355,7 @@ module ActiveRecord
362
355
 
363
356
  # Resets the sequence of a table's primary key to the maximum value.
364
357
  def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
365
- unless pk and sequence
358
+ unless pk && sequence
366
359
  default_pk, default_sequence = pk_and_sequence_for(table)
367
360
 
368
361
  pk ||= default_pk
@@ -375,17 +368,9 @@ module ActiveRecord
375
368
 
376
369
  if pk && sequence
377
370
  quoted_sequence = quote_table_name(sequence)
378
- max_pk = select_value("select MAX(#{quote_column_name pk}) from #{quote_table_name(table)}")
379
- if max_pk.nil?
380
- if postgresql_version >= 100000
381
- minvalue = select_value("SELECT seqmin from pg_sequence where seqrelid = '#{quoted_sequence}'::regclass")
382
- else
383
- minvalue = select_value("SELECT min_value FROM #{quoted_sequence}")
384
- end
385
- end
386
371
 
387
372
  select_value(<<-end_sql, "SCHEMA")
388
- SELECT setval('#{quoted_sequence}', #{max_pk ? max_pk : minvalue}, #{max_pk ? true : false})
373
+ SELECT setval('#{quoted_sequence}', (SELECT COALESCE(MAX(#{quote_column_name pk})+(SELECT increment_by FROM #{quoted_sequence}), (SELECT min_value FROM #{quoted_sequence})) FROM #{quote_table_name(table)}), false)
389
374
  end_sql
390
375
  end
391
376
  end
@@ -394,7 +379,7 @@ module ActiveRecord
394
379
  def pk_and_sequence_for(table) #:nodoc:
395
380
  # First try looking for a sequence with a dependency on the
396
381
  # given table's primary key.
397
- result = query(<<-end_sql, 'SCHEMA')[0]
382
+ result = query(<<-end_sql, "SCHEMA")[0]
398
383
  SELECT attr.attname, nsp.nspname, seq.relname
399
384
  FROM pg_class seq,
400
385
  pg_attribute attr,
@@ -413,8 +398,8 @@ module ActiveRecord
413
398
  AND dep.refobjid = '#{quote_table_name(table)}'::regclass
414
399
  end_sql
415
400
 
416
- if result.nil? or result.empty?
417
- result = query(<<-end_sql, 'SCHEMA')[0]
401
+ if result.nil? || result.empty?
402
+ result = query(<<-end_sql, "SCHEMA")[0]
418
403
  SELECT attr.attname, nsp.nspname,
419
404
  CASE
420
405
  WHEN pg_get_expr(def.adbin, def.adrelid) !~* 'nextval' THEN NULL
@@ -445,17 +430,18 @@ module ActiveRecord
445
430
  end
446
431
 
447
432
  def primary_keys(table_name) # :nodoc:
448
- select_values(<<-SQL.strip_heredoc, 'SCHEMA')
449
- WITH pk_constraint AS (
450
- SELECT conrelid, unnest(conkey) AS connum FROM pg_constraint
451
- WHERE contype = 'p'
452
- AND conrelid = '#{quote_table_name(table_name)}'::regclass
453
- ), cons AS (
454
- SELECT conrelid, connum, row_number() OVER() AS rownum FROM pk_constraint
455
- )
456
- SELECT attr.attname FROM pg_attribute attr
457
- INNER JOIN cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.connum
458
- ORDER BY cons.rownum
433
+ name = Utils.extract_schema_qualified_name(table_name.to_s)
434
+ select_values(<<-SQL.strip_heredoc, "SCHEMA")
435
+ SELECT column_name
436
+ FROM information_schema.key_column_usage kcu
437
+ JOIN information_schema.table_constraints tc
438
+ ON kcu.table_name = tc.table_name
439
+ AND kcu.table_schema = tc.table_schema
440
+ AND kcu.constraint_name = tc.constraint_name
441
+ WHERE constraint_type = 'PRIMARY KEY'
442
+ AND kcu.table_name = #{quote(name.identifier)}
443
+ AND kcu.table_schema = #{name.schema ? quote(name.schema) : "ANY (current_schemas(false))"}
444
+ ORDER BY kcu.ordinal_position
459
445
  SQL
460
446
  end
461
447
 
@@ -490,7 +476,7 @@ module ActiveRecord
490
476
  clear_cache!
491
477
  quoted_table_name = quote_table_name(table_name)
492
478
  quoted_column_name = quote_column_name(column_name)
493
- sql_type = type_to_sql(type, options[:limit], options[:precision], options[:scale], options[:array])
479
+ sql_type = type_to_sql(type, options)
494
480
  sql = "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quoted_column_name} TYPE #{sql_type}"
495
481
  if options[:collation]
496
482
  sql << " COLLATE \"#{options[:collation]}\""
@@ -498,7 +484,7 @@ module ActiveRecord
498
484
  if options[:using]
499
485
  sql << " USING #{options[:using]}"
500
486
  elsif options[:cast_as]
501
- cast_as_type = type_to_sql(options[:cast_as], options[:limit], options[:precision], options[:scale], options[:array])
487
+ cast_as_type = type_to_sql(options[:cast_as], options)
502
488
  sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
503
489
  end
504
490
  execute sql
@@ -593,7 +579,7 @@ module ActiveRecord
593
579
  end
594
580
 
595
581
  def foreign_keys(table_name)
596
- fk_info = select_all(<<-SQL.strip_heredoc, 'SCHEMA')
582
+ fk_info = select_all(<<-SQL.strip_heredoc, "SCHEMA")
597
583
  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
598
584
  FROM pg_constraint c
599
585
  JOIN pg_class t1 ON c.conrelid = t1.oid
@@ -609,70 +595,75 @@ module ActiveRecord
609
595
 
610
596
  fk_info.map do |row|
611
597
  options = {
612
- column: row['column'],
613
- name: row['name'],
614
- primary_key: row['primary_key']
598
+ column: row["column"],
599
+ name: row["name"],
600
+ primary_key: row["primary_key"]
615
601
  }
616
602
 
617
- options[:on_delete] = extract_foreign_key_action(row['on_delete'])
618
- options[:on_update] = extract_foreign_key_action(row['on_update'])
603
+ options[:on_delete] = extract_foreign_key_action(row["on_delete"])
604
+ options[:on_update] = extract_foreign_key_action(row["on_update"])
619
605
 
620
- ForeignKeyDefinition.new(table_name, row['to_table'], options)
606
+ ForeignKeyDefinition.new(table_name, row["to_table"], options)
621
607
  end
622
608
  end
623
609
 
624
610
  def extract_foreign_key_action(specifier) # :nodoc:
625
611
  case specifier
626
- when 'c'; :cascade
627
- when 'n'; :nullify
628
- when 'r'; :restrict
612
+ when "c"; :cascade
613
+ when "n"; :nullify
614
+ when "r"; :restrict
629
615
  end
630
616
  end
631
617
 
618
+ def index_name_length
619
+ 63
620
+ end
621
+
632
622
  # Maps logical Rails types to PostgreSQL-specific data types.
633
- def type_to_sql(type, limit = nil, precision = nil, scale = nil, array = nil)
634
- sql = case type.to_s
635
- when 'binary'
636
- # PostgreSQL doesn't support limits on binary (bytea) columns.
637
- # The hard limit is 1GB, because of a 32-bit size field, and TOAST.
638
- case limit
639
- when nil, 0..0x3fffffff; super(type)
640
- else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
641
- end
642
- when 'text'
643
- # PostgreSQL doesn't support limits on text columns.
644
- # The hard limit is 1GB, according to section 8.3 in the manual.
645
- case limit
646
- when nil, 0..0x3fffffff; super(type)
647
- else raise(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.")
648
- end
649
- when 'integer'
650
- case limit
651
- when 1, 2; 'smallint'
652
- when nil, 3, 4; 'integer'
653
- when 5..8; 'bigint'
654
- else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead.")
623
+ def type_to_sql(type, limit: nil, precision: nil, scale: nil, array: nil, **) # :nodoc:
624
+ sql = \
625
+ case type.to_s
626
+ when "binary"
627
+ # PostgreSQL doesn't support limits on binary (bytea) columns.
628
+ # The hard limit is 1GB, because of a 32-bit size field, and TOAST.
629
+ case limit
630
+ when nil, 0..0x3fffffff; super(type)
631
+ else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
632
+ end
633
+ when "text"
634
+ # PostgreSQL doesn't support limits on text columns.
635
+ # The hard limit is 1GB, according to section 8.3 in the manual.
636
+ case limit
637
+ when nil, 0..0x3fffffff; super(type)
638
+ else raise(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.")
639
+ end
640
+ when "integer"
641
+ case limit
642
+ when 1, 2; "smallint"
643
+ when nil, 3, 4; "integer"
644
+ when 5..8; "bigint"
645
+ else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead.")
646
+ end
647
+ else
648
+ super
655
649
  end
656
- else
657
- super(type, limit, precision, scale)
658
- end
659
650
 
660
- sql << '[]' if array && type != :primary_key
651
+ sql << "[]" if array && type != :primary_key
661
652
  sql
662
653
  end
663
654
 
664
655
  # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
665
656
  # requires that the ORDER BY include the distinct column.
666
657
  def columns_for_distinct(columns, orders) #:nodoc:
667
- order_columns = orders.reject(&:blank?).map{ |s|
658
+ order_columns = orders.reject(&:blank?).map { |s|
668
659
  # Convert Arel node to string
669
660
  s = s.to_sql unless s.is_a?(String)
670
661
  # Remove any ASC/DESC modifiers
671
- s.gsub(/\s+(?:ASC|DESC)\b/i, '')
672
- .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, '')
662
+ s.gsub(/\s+(?:ASC|DESC)\b/i, "")
663
+ .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "")
673
664
  }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
674
665
 
675
- [super, *order_columns].join(', ')
666
+ [super, *order_columns].join(", ")
676
667
  end
677
668
 
678
669
  def fetch_type_metadata(column_name, sql_type, oid, fmod)