activerecord 5.0.7 → 5.1.7

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 (219) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +657 -2080
  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/aggregations.rb +244 -244
  8. data/lib/active_record/association_relation.rb +5 -5
  9. data/lib/active_record/associations/alias_tracker.rb +10 -11
  10. data/lib/active_record/associations/association.rb +23 -5
  11. data/lib/active_record/associations/association_scope.rb +95 -81
  12. data/lib/active_record/associations/belongs_to_association.rb +7 -4
  13. data/lib/active_record/associations/builder/belongs_to.rb +30 -16
  14. data/lib/active_record/associations/builder/collection_association.rb +1 -2
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
  16. data/lib/active_record/associations/collection_association.rb +36 -205
  17. data/lib/active_record/associations/collection_proxy.rb +132 -63
  18. data/lib/active_record/associations/has_many_association.rb +10 -19
  19. data/lib/active_record/associations/has_many_through_association.rb +12 -4
  20. data/lib/active_record/associations/has_one_association.rb +24 -28
  21. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  22. data/lib/active_record/associations/join_dependency/join_association.rb +4 -28
  23. data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
  24. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  25. data/lib/active_record/associations/join_dependency.rb +121 -118
  26. data/lib/active_record/associations/preloader/association.rb +64 -64
  27. data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
  28. data/lib/active_record/associations/preloader/collection_association.rb +6 -6
  29. data/lib/active_record/associations/preloader/has_many.rb +0 -2
  30. data/lib/active_record/associations/preloader/singular_association.rb +6 -8
  31. data/lib/active_record/associations/preloader/through_association.rb +41 -41
  32. data/lib/active_record/associations/preloader.rb +94 -94
  33. data/lib/active_record/associations/singular_association.rb +8 -25
  34. data/lib/active_record/associations/through_association.rb +2 -5
  35. data/lib/active_record/associations.rb +1591 -1562
  36. data/lib/active_record/attribute/user_provided_default.rb +4 -2
  37. data/lib/active_record/attribute.rb +98 -71
  38. data/lib/active_record/attribute_assignment.rb +61 -61
  39. data/lib/active_record/attribute_decorators.rb +35 -13
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
  41. data/lib/active_record/attribute_methods/dirty.rb +229 -46
  42. data/lib/active_record/attribute_methods/primary_key.rb +74 -73
  43. data/lib/active_record/attribute_methods/read.rb +39 -35
  44. data/lib/active_record/attribute_methods/serialization.rb +7 -7
  45. data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
  46. data/lib/active_record/attribute_methods/write.rb +30 -33
  47. data/lib/active_record/attribute_methods.rb +56 -65
  48. data/lib/active_record/attribute_mutation_tracker.rb +63 -11
  49. data/lib/active_record/attribute_set/builder.rb +27 -33
  50. data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
  51. data/lib/active_record/attribute_set.rb +9 -6
  52. data/lib/active_record/attributes.rb +22 -22
  53. data/lib/active_record/autosave_association.rb +18 -13
  54. data/lib/active_record/base.rb +24 -22
  55. data/lib/active_record/callbacks.rb +56 -14
  56. data/lib/active_record/coders/yaml_column.rb +9 -11
  57. data/lib/active_record/collection_cache_key.rb +3 -4
  58. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +330 -284
  59. data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
  60. data/lib/active_record/connection_adapters/abstract/database_statements.rb +39 -37
  61. data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -27
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -51
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +10 -20
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +74 -79
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +120 -100
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +49 -43
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -135
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +404 -424
  70. data/lib/active_record/connection_adapters/column.rb +26 -4
  71. data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
  72. data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -49
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -28
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +7 -6
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +23 -27
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +32 -53
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +19 -9
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
  90. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
  91. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +0 -10
  92. data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
  93. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
  96. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +32 -30
  97. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
  99. data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
  100. data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -35
  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 +182 -222
  105. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +6 -4
  106. data/lib/active_record/connection_adapters/postgresql/utils.rb +7 -5
  107. data/lib/active_record/connection_adapters/postgresql_adapter.rb +198 -167
  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 -19
  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/schema_statements.rb +32 -0
  116. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +184 -167
  117. data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
  118. data/lib/active_record/connection_handling.rb +14 -26
  119. data/lib/active_record/core.rb +109 -93
  120. data/lib/active_record/counter_cache.rb +60 -13
  121. data/lib/active_record/define_callbacks.rb +20 -0
  122. data/lib/active_record/dynamic_matchers.rb +80 -79
  123. data/lib/active_record/enum.rb +8 -6
  124. data/lib/active_record/errors.rb +64 -15
  125. data/lib/active_record/explain.rb +1 -2
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +7 -4
  128. data/lib/active_record/fixture_set/file.rb +11 -8
  129. data/lib/active_record/fixtures.rb +66 -53
  130. data/lib/active_record/gem_version.rb +1 -1
  131. data/lib/active_record/inheritance.rb +93 -79
  132. data/lib/active_record/integration.rb +7 -7
  133. data/lib/active_record/internal_metadata.rb +3 -16
  134. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  135. data/lib/active_record/locking/optimistic.rb +69 -74
  136. data/lib/active_record/locking/pessimistic.rb +10 -1
  137. data/lib/active_record/log_subscriber.rb +23 -28
  138. data/lib/active_record/migration/command_recorder.rb +94 -94
  139. data/lib/active_record/migration/compatibility.rb +100 -47
  140. data/lib/active_record/migration/join_table.rb +6 -6
  141. data/lib/active_record/migration.rb +153 -155
  142. data/lib/active_record/model_schema.rb +94 -107
  143. data/lib/active_record/nested_attributes.rb +200 -199
  144. data/lib/active_record/null_relation.rb +11 -34
  145. data/lib/active_record/persistence.rb +65 -50
  146. data/lib/active_record/query_cache.rb +2 -6
  147. data/lib/active_record/querying.rb +3 -4
  148. data/lib/active_record/railtie.rb +16 -17
  149. data/lib/active_record/railties/controller_runtime.rb +6 -2
  150. data/lib/active_record/railties/databases.rake +105 -133
  151. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  152. data/lib/active_record/readonly_attributes.rb +2 -2
  153. data/lib/active_record/reflection.rb +154 -108
  154. data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
  155. data/lib/active_record/relation/batches.rb +80 -51
  156. data/lib/active_record/relation/calculations.rb +169 -162
  157. data/lib/active_record/relation/delegation.rb +32 -31
  158. data/lib/active_record/relation/finder_methods.rb +197 -231
  159. data/lib/active_record/relation/merger.rb +58 -62
  160. data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
  161. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
  162. data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
  163. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
  164. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
  165. data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
  166. data/lib/active_record/relation/predicate_builder.rb +92 -89
  167. data/lib/active_record/relation/query_attribute.rb +1 -1
  168. data/lib/active_record/relation/query_methods.rb +255 -293
  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 +80 -65
  172. data/lib/active_record/relation/where_clause_factory.rb +47 -8
  173. data/lib/active_record/relation.rb +93 -119
  174. data/lib/active_record/result.rb +41 -32
  175. data/lib/active_record/runtime_registry.rb +3 -3
  176. data/lib/active_record/sanitization.rb +176 -192
  177. data/lib/active_record/schema.rb +3 -3
  178. data/lib/active_record/schema_dumper.rb +15 -38
  179. data/lib/active_record/schema_migration.rb +8 -4
  180. data/lib/active_record/scoping/default.rb +90 -90
  181. data/lib/active_record/scoping/named.rb +11 -11
  182. data/lib/active_record/scoping.rb +6 -6
  183. data/lib/active_record/secure_token.rb +2 -2
  184. data/lib/active_record/statement_cache.rb +13 -15
  185. data/lib/active_record/store.rb +31 -32
  186. data/lib/active_record/suppressor.rb +2 -1
  187. data/lib/active_record/table_metadata.rb +9 -5
  188. data/lib/active_record/tasks/database_tasks.rb +65 -55
  189. data/lib/active_record/tasks/mysql_database_tasks.rb +76 -73
  190. data/lib/active_record/tasks/postgresql_database_tasks.rb +72 -47
  191. data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
  192. data/lib/active_record/timestamp.rb +46 -25
  193. data/lib/active_record/touch_later.rb +1 -2
  194. data/lib/active_record/transactions.rb +97 -109
  195. data/lib/active_record/type/adapter_specific_registry.rb +46 -42
  196. data/lib/active_record/type/decimal_without_scale.rb +13 -0
  197. data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
  198. data/lib/active_record/type/internal/abstract_json.rb +4 -0
  199. data/lib/active_record/type/serialized.rb +14 -8
  200. data/lib/active_record/type/text.rb +9 -0
  201. data/lib/active_record/type/time.rb +0 -1
  202. data/lib/active_record/type/type_map.rb +11 -15
  203. data/lib/active_record/type/unsigned_integer.rb +15 -0
  204. data/lib/active_record/type.rb +17 -13
  205. data/lib/active_record/type_caster/connection.rb +8 -6
  206. data/lib/active_record/type_caster/map.rb +3 -1
  207. data/lib/active_record/type_caster.rb +2 -2
  208. data/lib/active_record/validations/associated.rb +1 -1
  209. data/lib/active_record/validations/presence.rb +2 -2
  210. data/lib/active_record/validations/uniqueness.rb +8 -39
  211. data/lib/active_record/validations.rb +4 -4
  212. data/lib/active_record/version.rb +1 -1
  213. data/lib/active_record.rb +20 -20
  214. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
  215. data/lib/rails/generators/active_record/migration.rb +1 -1
  216. data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
  217. data/lib/rails/generators/active_record.rb +4 -4
  218. metadata +24 -13
  219. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -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
 
@@ -70,110 +54,49 @@ module ActiveRecord
70
54
  execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
71
55
  end
72
56
 
73
- # 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')
82
- end
83
-
84
- def data_sources # :nodoc
85
- select_values(<<-SQL, 'SCHEMA')
86
- SELECT c.relname
87
- FROM pg_class c
88
- 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
90
- AND n.nspname = ANY (current_schemas(false))
91
- SQL
92
- end
93
-
94
- # Returns true if table exists.
95
- # If the schema is not specified as part of +name+ then it will only find tables within
96
- # the current schema search path (regardless of permissions to access tables in other schemas)
97
- 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
- name = Utils.extract_schema_qualified_name(name.to_s)
109
- return false unless name.identifier
110
-
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))'}
118
- SQL
119
- end
120
-
121
- def views # :nodoc:
122
- select_values(<<-SQL, 'SCHEMA')
123
- SELECT c.relname
124
- FROM pg_class c
125
- 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))
128
- SQL
129
- end
130
-
131
- def view_exists?(view_name) # :nodoc:
132
- name = Utils.extract_schema_qualified_name(view_name.to_s)
133
- return false unless name.identifier
134
-
135
- select_values(<<-SQL, 'SCHEMA').any?
136
- SELECT c.relname
137
- FROM pg_class c
138
- LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
139
- 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))'}
142
- SQL
143
- end
144
-
145
57
  def drop_table(table_name, options = {}) # :nodoc:
146
58
  execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
147
59
  end
148
60
 
149
61
  # Returns true if schema exists.
150
62
  def schema_exists?(name)
151
- select_value("SELECT COUNT(*) FROM pg_namespace WHERE nspname = '#{name}'", 'SCHEMA').to_i > 0
63
+ query_value("SELECT COUNT(*) FROM pg_namespace WHERE nspname = #{quote(name)}", "SCHEMA").to_i > 0
152
64
  end
153
65
 
154
66
  # Verifies existence of an index with a given name.
155
- def index_name_exists?(table_name, index_name, default)
156
- table = Utils.extract_schema_qualified_name(table_name.to_s)
157
- index = Utils.extract_schema_qualified_name(index_name.to_s)
67
+ def index_name_exists?(table_name, index_name, default = nil)
68
+ unless default.nil?
69
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
70
+ Passing default to #index_name_exists? is deprecated without replacement.
71
+ MSG
72
+ end
73
+ table = quoted_scope(table_name)
74
+ index = quoted_scope(index_name)
158
75
 
159
- select_value(<<-SQL, 'SCHEMA').to_i > 0
76
+ query_value(<<-SQL, "SCHEMA").to_i > 0
160
77
  SELECT COUNT(*)
161
78
  FROM pg_class t
162
79
  INNER JOIN pg_index d ON t.oid = d.indrelid
163
80
  INNER JOIN pg_class i ON d.indexrelid = i.oid
164
81
  LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
165
82
  WHERE i.relkind = 'i'
166
- AND i.relname = '#{index.identifier}'
167
- AND t.relname = '#{table.identifier}'
168
- AND n.nspname = #{index.schema ? "'#{index.schema}'" : 'ANY (current_schemas(false))'}
83
+ AND i.relname = #{index[:name]}
84
+ AND t.relname = #{table[:name]}
85
+ AND n.nspname = #{index[:schema]}
169
86
  SQL
170
87
  end
171
88
 
172
89
  # Returns an array of indexes for the given table.
173
- def indexes(table_name, name = nil)
174
- table = Utils.extract_schema_qualified_name(table_name.to_s)
90
+ def indexes(table_name, name = nil) # :nodoc:
91
+ if name
92
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
93
+ Passing name to #indexes is deprecated without replacement.
94
+ MSG
95
+ end
175
96
 
176
- result = query(<<-SQL, 'SCHEMA')
97
+ scope = quoted_scope(table_name)
98
+
99
+ result = query(<<-SQL, "SCHEMA")
177
100
  SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid,
178
101
  pg_catalog.obj_description(i.oid, 'pg_class') AS comment,
179
102
  (SELECT COUNT(*) FROM pg_opclass o
@@ -185,8 +108,8 @@ module ActiveRecord
185
108
  LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
186
109
  WHERE i.relkind = 'i'
187
110
  AND d.indisprimary = 'f'
188
- AND t.relname = '#{table.identifier}'
189
- AND n.nspname = #{table.schema ? "'#{table.schema}'" : 'ANY (current_schemas(false))'}
111
+ AND t.relname = #{scope[:name]}
112
+ AND n.nspname = #{scope[:schema]}
190
113
  ORDER BY i.relname
191
114
  SQL
192
115
 
@@ -199,7 +122,7 @@ module ActiveRecord
199
122
  comment = row[5]
200
123
  opclass = row[6]
201
124
 
202
- using, expressions, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: WHERE (.+))?\z/).flatten
125
+ using, expressions, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: WHERE (.+))?\z/m).flatten
203
126
 
204
127
  if indkey.include?(0) || opclass > 0
205
128
  columns = expressions
@@ -221,21 +144,24 @@ module ActiveRecord
221
144
  end.compact
222
145
  end
223
146
 
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)
147
+ def new_column_from_field(table_name, field) # :nondoc:
148
+ column_name, type, default, notnull, oid, fmod, collation, comment = field
149
+ oid = oid.to_i
150
+ fmod = fmod.to_i
151
+ type_metadata = fetch_type_metadata(column_name, type, oid, fmod)
152
+ default_value = extract_value_from_default(default)
153
+ default_function = extract_default_function(default_value, default)
154
+ PostgreSQLColumn.new(
155
+ column_name,
156
+ default_value,
157
+ type_metadata,
158
+ !notnull,
159
+ table_name,
160
+ default_function,
161
+ collation,
162
+ comment: comment.presence,
163
+ max_identifier_length: max_identifier_length
164
+ )
239
165
  end
240
166
 
241
167
  def table_options(table_name) # :nodoc:
@@ -246,47 +172,47 @@ module ActiveRecord
246
172
 
247
173
  # Returns a comment stored in database for given table
248
174
  def table_comment(table_name) # :nodoc:
249
- name = Utils.extract_schema_qualified_name(table_name.to_s)
250
- if name.identifier
251
- select_value(<<-SQL.strip_heredoc, 'SCHEMA')
175
+ scope = quoted_scope(table_name, type: "BASE TABLE")
176
+ if scope[:name]
177
+ query_value(<<-SQL.strip_heredoc, "SCHEMA")
252
178
  SELECT pg_catalog.obj_description(c.oid, 'pg_class')
253
179
  FROM pg_catalog.pg_class c
254
180
  LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
255
- WHERE c.relname = #{quote(name.identifier)}
256
- AND c.relkind IN ('r') -- (r)elation/table
257
- AND n.nspname = #{name.schema ? quote(name.schema) : 'ANY (current_schemas(false))'}
181
+ WHERE c.relname = #{scope[:name]}
182
+ AND c.relkind IN (#{scope[:type]})
183
+ AND n.nspname = #{scope[:schema]}
258
184
  SQL
259
185
  end
260
186
  end
261
187
 
262
188
  # Returns the current database name.
263
189
  def current_database
264
- select_value('select current_database()', 'SCHEMA')
190
+ query_value("SELECT current_database()", "SCHEMA")
265
191
  end
266
192
 
267
193
  # Returns the current schema name.
268
194
  def current_schema
269
- select_value('SELECT current_schema', 'SCHEMA')
195
+ query_value("SELECT current_schema", "SCHEMA")
270
196
  end
271
197
 
272
198
  # Returns the current database encoding format.
273
199
  def encoding
274
- select_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA')
200
+ query_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = current_database()", "SCHEMA")
275
201
  end
276
202
 
277
203
  # Returns the current database collation.
278
204
  def collation
279
- select_value("SELECT datcollate FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA')
205
+ query_value("SELECT datcollate FROM pg_database WHERE datname = current_database()", "SCHEMA")
280
206
  end
281
207
 
282
208
  # Returns the current database ctype.
283
209
  def ctype
284
- select_value("SELECT datctype FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA')
210
+ query_value("SELECT datctype FROM pg_database WHERE datname = current_database()", "SCHEMA")
285
211
  end
286
212
 
287
213
  # Returns an array of schema names.
288
214
  def schema_names
289
- select_values(<<-SQL, 'SCHEMA')
215
+ query_values(<<-SQL, "SCHEMA")
290
216
  SELECT nspname
291
217
  FROM pg_namespace
292
218
  WHERE nspname !~ '^pg_.*'
@@ -296,7 +222,7 @@ module ActiveRecord
296
222
  end
297
223
 
298
224
  # Creates a schema for the given schema name.
299
- def create_schema schema_name
225
+ def create_schema(schema_name)
300
226
  execute "CREATE SCHEMA #{quote_schema_name(schema_name)}"
301
227
  end
302
228
 
@@ -312,37 +238,37 @@ module ActiveRecord
312
238
  # This should be not be called manually but set in database.yml.
313
239
  def schema_search_path=(schema_csv)
314
240
  if schema_csv
315
- execute("SET search_path TO #{schema_csv}", 'SCHEMA')
241
+ execute("SET search_path TO #{schema_csv}", "SCHEMA")
316
242
  @schema_search_path = schema_csv
317
243
  end
318
244
  end
319
245
 
320
246
  # Returns the active schema search path.
321
247
  def schema_search_path
322
- @schema_search_path ||= select_value('SHOW search_path', 'SCHEMA')
248
+ @schema_search_path ||= query_value("SHOW search_path", "SCHEMA")
323
249
  end
324
250
 
325
251
  # Returns the current client message level.
326
252
  def client_min_messages
327
- select_value('SHOW client_min_messages', 'SCHEMA')
253
+ query_value("SHOW client_min_messages", "SCHEMA")
328
254
  end
329
255
 
330
256
  # Set the client message level.
331
257
  def client_min_messages=(level)
332
- execute("SET client_min_messages TO '#{level}'", 'SCHEMA')
258
+ execute("SET client_min_messages TO '#{level}'", "SCHEMA")
333
259
  end
334
260
 
335
261
  # 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')
262
+ def default_sequence_name(table_name, pk = "id") #:nodoc:
263
+ result = serial_sequence(table_name, pk)
338
264
  return nil unless result
339
265
  Utils.extract_schema_qualified_name(result).to_s
340
266
  rescue ActiveRecord::StatementInvalid
341
- PostgreSQL::Name.new(nil, "#{table_name}_#{pk || 'id'}_seq").to_s
267
+ PostgreSQL::Name.new(nil, "#{table_name}_#{pk}_seq").to_s
342
268
  end
343
269
 
344
270
  def serial_sequence(table, column)
345
- select_value("SELECT pg_get_serial_sequence('#{table}', '#{column}')", 'SCHEMA')
271
+ query_value("SELECT pg_get_serial_sequence(#{quote(table)}, #{quote(column)})", "SCHEMA")
346
272
  end
347
273
 
348
274
  # Sets the sequence of a table's primary key to the specified value.
@@ -353,7 +279,7 @@ module ActiveRecord
353
279
  if sequence
354
280
  quoted_sequence = quote_table_name(sequence)
355
281
 
356
- select_value("SELECT setval('#{quoted_sequence}', #{value})", 'SCHEMA')
282
+ query_value("SELECT setval(#{quote(quoted_sequence)}, #{value})", "SCHEMA")
357
283
  else
358
284
  @logger.warn "#{table} has primary key #{pk} with no default sequence." if @logger
359
285
  end
@@ -362,7 +288,7 @@ module ActiveRecord
362
288
 
363
289
  # Resets the sequence of a table's primary key to the maximum value.
364
290
  def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
365
- unless pk and sequence
291
+ unless pk && sequence
366
292
  default_pk, default_sequence = pk_and_sequence_for(table)
367
293
 
368
294
  pk ||= default_pk
@@ -375,18 +301,16 @@ module ActiveRecord
375
301
 
376
302
  if pk && sequence
377
303
  quoted_sequence = quote_table_name(sequence)
378
- max_pk = select_value("select MAX(#{quote_column_name pk}) from #{quote_table_name(table)}")
304
+ max_pk = query_value("SELECT MAX(#{quote_column_name pk}) FROM #{quote_table_name(table)}", "SCHEMA")
379
305
  if max_pk.nil?
380
306
  if postgresql_version >= 100000
381
- minvalue = select_value("SELECT seqmin from pg_sequence where seqrelid = '#{quoted_sequence}'::regclass")
307
+ minvalue = query_value("SELECT seqmin FROM pg_sequence WHERE seqrelid = #{quote(quoted_sequence)}::regclass", "SCHEMA")
382
308
  else
383
- minvalue = select_value("SELECT min_value FROM #{quoted_sequence}")
309
+ minvalue = query_value("SELECT min_value FROM #{quoted_sequence}", "SCHEMA")
384
310
  end
385
311
  end
386
312
 
387
- select_value(<<-end_sql, "SCHEMA")
388
- SELECT setval('#{quoted_sequence}', #{max_pk ? max_pk : minvalue}, #{max_pk ? true : false})
389
- end_sql
313
+ query_value("SELECT setval(#{quote(quoted_sequence)}, #{max_pk ? max_pk : minvalue}, #{max_pk ? true : false})", "SCHEMA")
390
314
  end
391
315
  end
392
316
 
@@ -394,7 +318,7 @@ module ActiveRecord
394
318
  def pk_and_sequence_for(table) #:nodoc:
395
319
  # First try looking for a sequence with a dependency on the
396
320
  # given table's primary key.
397
- result = query(<<-end_sql, 'SCHEMA')[0]
321
+ result = query(<<-end_sql, "SCHEMA")[0]
398
322
  SELECT attr.attname, nsp.nspname, seq.relname
399
323
  FROM pg_class seq,
400
324
  pg_attribute attr,
@@ -413,8 +337,8 @@ module ActiveRecord
413
337
  AND dep.refobjid = '#{quote_table_name(table)}'::regclass
414
338
  end_sql
415
339
 
416
- if result.nil? or result.empty?
417
- result = query(<<-end_sql, 'SCHEMA')[0]
340
+ if result.nil? || result.empty?
341
+ result = query(<<-end_sql, "SCHEMA")[0]
418
342
  SELECT attr.attname, nsp.nspname,
419
343
  CASE
420
344
  WHEN pg_get_expr(def.adbin, def.adrelid) !~* 'nextval' THEN NULL
@@ -445,17 +369,18 @@ module ActiveRecord
445
369
  end
446
370
 
447
371
  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
372
+ query_values(<<-SQL.strip_heredoc, "SCHEMA")
373
+ SELECT a.attname
374
+ FROM (
375
+ SELECT indrelid, indkey, generate_subscripts(indkey, 1) idx
376
+ FROM pg_index
377
+ WHERE indrelid = #{quote(quote_table_name(table_name))}::regclass
378
+ AND indisprimary
379
+ ) i
380
+ JOIN pg_attribute a
381
+ ON a.attrelid = i.indrelid
382
+ AND a.attnum = i.indkey[i.idx]
383
+ ORDER BY i.idx
459
384
  SQL
460
385
  end
461
386
 
@@ -490,7 +415,7 @@ module ActiveRecord
490
415
  clear_cache!
491
416
  quoted_table_name = quote_table_name(table_name)
492
417
  quoted_column_name = quote_column_name(column_name)
493
- sql_type = type_to_sql(type, options[:limit], options[:precision], options[:scale], options[:array])
418
+ sql_type = type_to_sql(type, options)
494
419
  sql = "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quoted_column_name} TYPE #{sql_type}"
495
420
  if options[:collation]
496
421
  sql << " COLLATE \"#{options[:collation]}\""
@@ -498,12 +423,12 @@ module ActiveRecord
498
423
  if options[:using]
499
424
  sql << " USING #{options[:using]}"
500
425
  elsif options[:cast_as]
501
- cast_as_type = type_to_sql(options[:cast_as], options[:limit], options[:precision], options[:scale], options[:array])
426
+ cast_as_type = type_to_sql(options[:cast_as], options)
502
427
  sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
503
428
  end
504
429
  execute sql
505
430
 
506
- change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
431
+ change_column_default(table_name, column_name, options[:default]) if options.key?(:default)
507
432
  change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
508
433
  change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
509
434
  end
@@ -593,7 +518,8 @@ module ActiveRecord
593
518
  end
594
519
 
595
520
  def foreign_keys(table_name)
596
- fk_info = select_all(<<-SQL.strip_heredoc, 'SCHEMA')
521
+ scope = quoted_scope(table_name)
522
+ fk_info = exec_query(<<-SQL.strip_heredoc, "SCHEMA")
597
523
  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
524
  FROM pg_constraint c
599
525
  JOIN pg_class t1 ON c.conrelid = t1.oid
@@ -602,77 +528,78 @@ module ActiveRecord
602
528
  JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
603
529
  JOIN pg_namespace t3 ON c.connamespace = t3.oid
604
530
  WHERE c.contype = 'f'
605
- AND t1.relname = #{quote(table_name)}
606
- AND t3.nspname = ANY (current_schemas(false))
531
+ AND t1.relname = #{scope[:name]}
532
+ AND t3.nspname = #{scope[:schema]}
607
533
  ORDER BY c.conname
608
534
  SQL
609
535
 
610
536
  fk_info.map do |row|
611
537
  options = {
612
- column: row['column'],
613
- name: row['name'],
614
- primary_key: row['primary_key']
538
+ column: row["column"],
539
+ name: row["name"],
540
+ primary_key: row["primary_key"]
615
541
  }
616
542
 
617
- options[:on_delete] = extract_foreign_key_action(row['on_delete'])
618
- options[:on_update] = extract_foreign_key_action(row['on_update'])
543
+ options[:on_delete] = extract_foreign_key_action(row["on_delete"])
544
+ options[:on_update] = extract_foreign_key_action(row["on_update"])
619
545
 
620
- ForeignKeyDefinition.new(table_name, row['to_table'], options)
546
+ ForeignKeyDefinition.new(table_name, row["to_table"], options)
621
547
  end
622
548
  end
623
549
 
624
550
  def extract_foreign_key_action(specifier) # :nodoc:
625
551
  case specifier
626
- when 'c'; :cascade
627
- when 'n'; :nullify
628
- when 'r'; :restrict
552
+ when "c"; :cascade
553
+ when "n"; :nullify
554
+ when "r"; :restrict
629
555
  end
630
556
  end
631
557
 
632
558
  # 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.")
559
+ def type_to_sql(type, limit: nil, precision: nil, scale: nil, array: nil, **) # :nodoc:
560
+ sql = \
561
+ case type.to_s
562
+ when "binary"
563
+ # PostgreSQL doesn't support limits on binary (bytea) columns.
564
+ # The hard limit is 1GB, because of a 32-bit size field, and TOAST.
565
+ case limit
566
+ when nil, 0..0x3fffffff; super(type)
567
+ else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
568
+ end
569
+ when "text"
570
+ # PostgreSQL doesn't support limits on text columns.
571
+ # The hard limit is 1GB, according to section 8.3 in the manual.
572
+ case limit
573
+ when nil, 0..0x3fffffff; super(type)
574
+ else raise(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.")
575
+ end
576
+ when "integer"
577
+ case limit
578
+ when 1, 2; "smallint"
579
+ when nil, 3, 4; "integer"
580
+ when 5..8; "bigint"
581
+ else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead.")
582
+ end
583
+ else
584
+ super
655
585
  end
656
- else
657
- super(type, limit, precision, scale)
658
- end
659
586
 
660
- sql << '[]' if array && type != :primary_key
587
+ sql << "[]" if array && type != :primary_key
661
588
  sql
662
589
  end
663
590
 
664
591
  # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
665
592
  # requires that the ORDER BY include the distinct column.
666
593
  def columns_for_distinct(columns, orders) #:nodoc:
667
- order_columns = orders.reject(&:blank?).map{ |s|
594
+ order_columns = orders.reject(&:blank?).map { |s|
668
595
  # Convert Arel node to string
669
596
  s = s.to_sql unless s.is_a?(String)
670
597
  # Remove any ASC/DESC modifiers
671
- s.gsub(/\s+(?:ASC|DESC)\b/i, '')
672
- .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, '')
598
+ s.gsub(/\s+(?:ASC|DESC)\b/i, "")
599
+ .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "")
673
600
  }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
674
601
 
675
- [super, *order_columns].join(', ')
602
+ [super, *order_columns].join(", ")
676
603
  end
677
604
 
678
605
  def fetch_type_metadata(column_name, sql_type, oid, fmod)
@@ -686,6 +613,39 @@ module ActiveRecord
686
613
  )
687
614
  PostgreSQLTypeMetadata.new(simple_type, oid: oid, fmod: fmod)
688
615
  end
616
+
617
+ private
618
+ def data_source_sql(name = nil, type: nil)
619
+ scope = quoted_scope(name, type: type)
620
+ scope[:type] ||= "'r','v','m'" # (r)elation/table, (v)iew, (m)aterialized view
621
+
622
+ sql = "SELECT c.relname FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace"
623
+ sql << " WHERE n.nspname = #{scope[:schema]}"
624
+ sql << " AND c.relname = #{scope[:name]}" if scope[:name]
625
+ sql << " AND c.relkind IN (#{scope[:type]})"
626
+ sql
627
+ end
628
+
629
+ def quoted_scope(name = nil, type: nil)
630
+ schema, name = extract_schema_qualified_name(name)
631
+ type = \
632
+ case type
633
+ when "BASE TABLE"
634
+ "'r'"
635
+ when "VIEW"
636
+ "'v','m'"
637
+ end
638
+ scope = {}
639
+ scope[:schema] = schema ? quote(schema) : "ANY (current_schemas(false))"
640
+ scope[:name] = quote(name) if name
641
+ scope[:type] = type if type
642
+ scope
643
+ end
644
+
645
+ def extract_schema_qualified_name(string)
646
+ name = Utils.extract_schema_qualified_name(string.to_s)
647
+ [name.schema, name.identifier]
648
+ end
689
649
  end
690
650
  end
691
651
  end