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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +657 -2080
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/examples/performance.rb +28 -28
- data/examples/simple.rb +3 -3
- data/lib/active_record/aggregations.rb +244 -244
- data/lib/active_record/association_relation.rb +5 -5
- data/lib/active_record/associations/alias_tracker.rb +10 -11
- data/lib/active_record/associations/association.rb +23 -5
- data/lib/active_record/associations/association_scope.rb +95 -81
- data/lib/active_record/associations/belongs_to_association.rb +7 -4
- data/lib/active_record/associations/builder/belongs_to.rb +30 -16
- data/lib/active_record/associations/builder/collection_association.rb +1 -2
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
- data/lib/active_record/associations/collection_association.rb +36 -205
- data/lib/active_record/associations/collection_proxy.rb +132 -63
- data/lib/active_record/associations/has_many_association.rb +10 -19
- data/lib/active_record/associations/has_many_through_association.rb +12 -4
- data/lib/active_record/associations/has_one_association.rb +24 -28
- data/lib/active_record/associations/has_one_through_association.rb +5 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +4 -28
- data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +121 -118
- data/lib/active_record/associations/preloader/association.rb +64 -64
- data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
- data/lib/active_record/associations/preloader/collection_association.rb +6 -6
- data/lib/active_record/associations/preloader/has_many.rb +0 -2
- data/lib/active_record/associations/preloader/singular_association.rb +6 -8
- data/lib/active_record/associations/preloader/through_association.rb +41 -41
- data/lib/active_record/associations/preloader.rb +94 -94
- data/lib/active_record/associations/singular_association.rb +8 -25
- data/lib/active_record/associations/through_association.rb +2 -5
- data/lib/active_record/associations.rb +1591 -1562
- data/lib/active_record/attribute/user_provided_default.rb +4 -2
- data/lib/active_record/attribute.rb +98 -71
- data/lib/active_record/attribute_assignment.rb +61 -61
- data/lib/active_record/attribute_decorators.rb +35 -13
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
- data/lib/active_record/attribute_methods/dirty.rb +229 -46
- data/lib/active_record/attribute_methods/primary_key.rb +74 -73
- data/lib/active_record/attribute_methods/read.rb +39 -35
- data/lib/active_record/attribute_methods/serialization.rb +7 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
- data/lib/active_record/attribute_methods/write.rb +30 -33
- data/lib/active_record/attribute_methods.rb +56 -65
- data/lib/active_record/attribute_mutation_tracker.rb +63 -11
- data/lib/active_record/attribute_set/builder.rb +27 -33
- data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
- data/lib/active_record/attribute_set.rb +9 -6
- data/lib/active_record/attributes.rb +22 -22
- data/lib/active_record/autosave_association.rb +18 -13
- data/lib/active_record/base.rb +24 -22
- data/lib/active_record/callbacks.rb +56 -14
- data/lib/active_record/coders/yaml_column.rb +9 -11
- data/lib/active_record/collection_cache_key.rb +3 -4
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +330 -284
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +39 -37
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -51
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +10 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +74 -79
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/abstract/transaction.rb +49 -43
- data/lib/active_record/connection_adapters/abstract_adapter.rb +165 -135
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +404 -424
- data/lib/active_record/connection_adapters/column.rb +26 -4
- data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
- data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -49
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
- data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -28
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +7 -6
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +23 -27
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +32 -53
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +0 -10
- data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +32 -30
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
- data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -35
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +182 -222
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +6 -4
- data/lib/active_record/connection_adapters/postgresql/utils.rb +7 -5
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +198 -167
- data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -19
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +184 -167
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
- data/lib/active_record/connection_handling.rb +14 -26
- data/lib/active_record/core.rb +109 -93
- data/lib/active_record/counter_cache.rb +60 -13
- data/lib/active_record/define_callbacks.rb +20 -0
- data/lib/active_record/dynamic_matchers.rb +80 -79
- data/lib/active_record/enum.rb +8 -6
- data/lib/active_record/errors.rb +64 -15
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +7 -4
- data/lib/active_record/fixture_set/file.rb +11 -8
- data/lib/active_record/fixtures.rb +66 -53
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +93 -79
- data/lib/active_record/integration.rb +7 -7
- data/lib/active_record/internal_metadata.rb +3 -16
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +69 -74
- data/lib/active_record/locking/pessimistic.rb +10 -1
- data/lib/active_record/log_subscriber.rb +23 -28
- data/lib/active_record/migration/command_recorder.rb +94 -94
- data/lib/active_record/migration/compatibility.rb +100 -47
- data/lib/active_record/migration/join_table.rb +6 -6
- data/lib/active_record/migration.rb +153 -155
- data/lib/active_record/model_schema.rb +94 -107
- data/lib/active_record/nested_attributes.rb +200 -199
- data/lib/active_record/null_relation.rb +11 -34
- data/lib/active_record/persistence.rb +65 -50
- data/lib/active_record/query_cache.rb +2 -6
- data/lib/active_record/querying.rb +3 -4
- data/lib/active_record/railtie.rb +16 -17
- data/lib/active_record/railties/controller_runtime.rb +6 -2
- data/lib/active_record/railties/databases.rake +105 -133
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -2
- data/lib/active_record/reflection.rb +154 -108
- data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
- data/lib/active_record/relation/batches.rb +80 -51
- data/lib/active_record/relation/calculations.rb +169 -162
- data/lib/active_record/relation/delegation.rb +32 -31
- data/lib/active_record/relation/finder_methods.rb +197 -231
- data/lib/active_record/relation/merger.rb +58 -62
- data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
- data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
- data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
- data/lib/active_record/relation/predicate_builder.rb +92 -89
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +255 -293
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +4 -5
- data/lib/active_record/relation/where_clause.rb +80 -65
- data/lib/active_record/relation/where_clause_factory.rb +47 -8
- data/lib/active_record/relation.rb +93 -119
- data/lib/active_record/result.rb +41 -32
- data/lib/active_record/runtime_registry.rb +3 -3
- data/lib/active_record/sanitization.rb +176 -192
- data/lib/active_record/schema.rb +3 -3
- data/lib/active_record/schema_dumper.rb +15 -38
- data/lib/active_record/schema_migration.rb +8 -4
- data/lib/active_record/scoping/default.rb +90 -90
- data/lib/active_record/scoping/named.rb +11 -11
- data/lib/active_record/scoping.rb +6 -6
- data/lib/active_record/secure_token.rb +2 -2
- data/lib/active_record/statement_cache.rb +13 -15
- data/lib/active_record/store.rb +31 -32
- data/lib/active_record/suppressor.rb +2 -1
- data/lib/active_record/table_metadata.rb +9 -5
- data/lib/active_record/tasks/database_tasks.rb +65 -55
- data/lib/active_record/tasks/mysql_database_tasks.rb +76 -73
- data/lib/active_record/tasks/postgresql_database_tasks.rb +72 -47
- data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
- data/lib/active_record/timestamp.rb +46 -25
- data/lib/active_record/touch_later.rb +1 -2
- data/lib/active_record/transactions.rb +97 -109
- data/lib/active_record/type/adapter_specific_registry.rb +46 -42
- data/lib/active_record/type/decimal_without_scale.rb +13 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
- data/lib/active_record/type/internal/abstract_json.rb +4 -0
- data/lib/active_record/type/serialized.rb +14 -8
- data/lib/active_record/type/text.rb +9 -0
- data/lib/active_record/type/time.rb +0 -1
- data/lib/active_record/type/type_map.rb +11 -15
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type.rb +17 -13
- data/lib/active_record/type_caster/connection.rb +8 -6
- data/lib/active_record/type_caster/map.rb +3 -1
- data/lib/active_record/type_caster.rb +2 -2
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +8 -39
- data/lib/active_record/validations.rb +4 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +20 -20
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
- data/lib/rails/generators/active_record/migration.rb +1 -1
- data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
- data/lib/rails/generators/active_record.rb +4 -4
- metadata +24 -13
- data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -1,24 +1,8 @@
|
|
1
|
-
require
|
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:
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
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
|
-
|
157
|
-
|
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
|
-
|
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 =
|
167
|
-
AND t.relname =
|
168
|
-
AND n.nspname = #{index
|
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
|
-
|
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
|
-
|
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 =
|
189
|
-
AND n.nspname = #{
|
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
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
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
|
-
|
250
|
-
if name
|
251
|
-
|
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 = #{
|
256
|
-
AND c.relkind IN (
|
257
|
-
AND n.nspname = #{
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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}",
|
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 ||=
|
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
|
-
|
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}'",
|
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 =
|
337
|
-
result = serial_sequence(table_name, pk
|
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
|
267
|
+
PostgreSQL::Name.new(nil, "#{table_name}_#{pk}_seq").to_s
|
342
268
|
end
|
343
269
|
|
344
270
|
def serial_sequence(table, column)
|
345
|
-
|
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
|
-
|
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
|
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 =
|
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 =
|
307
|
+
minvalue = query_value("SELECT seqmin FROM pg_sequence WHERE seqrelid = #{quote(quoted_sequence)}::regclass", "SCHEMA")
|
382
308
|
else
|
383
|
-
minvalue =
|
309
|
+
minvalue = query_value("SELECT min_value FROM #{quoted_sequence}", "SCHEMA")
|
384
310
|
end
|
385
311
|
end
|
386
312
|
|
387
|
-
|
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,
|
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?
|
417
|
-
result = query(<<-end_sql,
|
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
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
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
|
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
|
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
|
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
|
-
|
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 = #{
|
606
|
-
AND t3.nspname =
|
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[
|
613
|
-
name: row[
|
614
|
-
primary_key: row[
|
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[
|
618
|
-
options[:on_update] = extract_foreign_key_action(row[
|
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[
|
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
|
627
|
-
when
|
628
|
-
when
|
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
|
634
|
-
sql =
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
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 <<
|
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
|