activerecord 4.2.0 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1537 -789
- data/MIT-LICENSE +2 -2
- data/README.rdoc +7 -8
- data/examples/performance.rb +2 -3
- data/examples/simple.rb +0 -1
- data/lib/active_record/aggregations.rb +37 -23
- data/lib/active_record/association_relation.rb +16 -3
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +23 -9
- data/lib/active_record/associations/association_scope.rb +74 -102
- data/lib/active_record/associations/belongs_to_association.rb +26 -29
- data/lib/active_record/associations/builder/association.rb +28 -34
- data/lib/active_record/associations/builder/belongs_to.rb +43 -18
- data/lib/active_record/associations/builder/collection_association.rb +12 -20
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +22 -15
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +11 -6
- data/lib/active_record/associations/builder/singular_association.rb +3 -10
- data/lib/active_record/associations/collection_association.rb +61 -33
- data/lib/active_record/associations/collection_proxy.rb +81 -35
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +21 -57
- data/lib/active_record/associations/has_many_through_association.rb +15 -45
- data/lib/active_record/associations/has_one_association.rb +13 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
- data/lib/active_record/associations/join_dependency.rb +37 -21
- data/lib/active_record/associations/preloader/association.rb +51 -53
- data/lib/active_record/associations/preloader/collection_association.rb +0 -6
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/through_association.rb +27 -14
- data/lib/active_record/associations/preloader.rb +18 -8
- data/lib/active_record/associations/singular_association.rb +8 -8
- data/lib/active_record/associations/through_association.rb +22 -9
- data/lib/active_record/associations.rb +321 -212
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +79 -15
- data/lib/active_record/attribute_assignment.rb +20 -141
- data/lib/active_record/attribute_decorators.rb +6 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +6 -1
- data/lib/active_record/attribute_methods/dirty.rb +51 -81
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +31 -59
- data/lib/active_record/attribute_methods/serialization.rb +13 -16
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -14
- data/lib/active_record/attribute_methods/write.rb +14 -38
- data/lib/active_record/attribute_methods.rb +70 -45
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +37 -15
- data/lib/active_record/attribute_set.rb +34 -3
- data/lib/active_record/attributes.rb +199 -73
- data/lib/active_record/autosave_association.rb +73 -25
- data/lib/active_record/base.rb +35 -27
- data/lib/active_record/callbacks.rb +39 -43
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +20 -8
- data/lib/active_record/collection_cache_key.rb +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +457 -181
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -59
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -4
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +246 -185
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +438 -136
- data/lib/active_record/connection_adapters/abstract/transaction.rb +53 -40
- data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -66
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +429 -335
- data/lib/active_record/connection_adapters/column.rb +28 -43
- data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -177
- data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +11 -73
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -56
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -13
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +248 -154
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +258 -170
- data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +150 -209
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +38 -15
- data/lib/active_record/core.rb +109 -114
- data/lib/active_record/counter_cache.rb +14 -25
- data/lib/active_record/dynamic_matchers.rb +1 -20
- data/lib/active_record/enum.rb +115 -79
- data/lib/active_record/errors.rb +88 -48
- data/lib/active_record/explain_registry.rb +1 -1
- data/lib/active_record/explain_subscriber.rb +2 -2
- data/lib/active_record/fixture_set/file.rb +26 -5
- data/lib/active_record/fixtures.rb +84 -46
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +32 -40
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +46 -0
- data/lib/active_record/locale/en.yml +3 -2
- data/lib/active_record/locking/optimistic.rb +27 -25
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +43 -21
- data/lib/active_record/migration/command_recorder.rb +59 -18
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration.rb +372 -114
- data/lib/active_record/model_schema.rb +128 -38
- data/lib/active_record/nested_attributes.rb +71 -32
- data/lib/active_record/no_touching.rb +1 -1
- data/lib/active_record/null_relation.rb +16 -8
- data/lib/active_record/persistence.rb +124 -80
- data/lib/active_record/query_cache.rb +15 -18
- data/lib/active_record/querying.rb +10 -9
- data/lib/active_record/railtie.rb +28 -19
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +67 -51
- data/lib/active_record/readonly_attributes.rb +1 -1
- data/lib/active_record/reflection.rb +318 -139
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +139 -34
- data/lib/active_record/relation/calculations.rb +80 -102
- data/lib/active_record/relation/delegation.rb +7 -20
- data/lib/active_record/relation/finder_methods.rb +167 -97
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +38 -41
- data/lib/active_record/relation/predicate_builder/array_handler.rb +12 -16
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +124 -82
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +323 -257
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +11 -10
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/relation.rb +176 -115
- data/lib/active_record/result.rb +4 -3
- data/lib/active_record/runtime_registry.rb +1 -1
- data/lib/active_record/sanitization.rb +95 -66
- data/lib/active_record/schema.rb +26 -22
- data/lib/active_record/schema_dumper.rb +62 -38
- data/lib/active_record/schema_migration.rb +11 -17
- data/lib/active_record/scoping/default.rb +24 -9
- data/lib/active_record/scoping/named.rb +49 -28
- data/lib/active_record/scoping.rb +32 -15
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +2 -4
- data/lib/active_record/statement_cache.rb +16 -14
- data/lib/active_record/store.rb +8 -3
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +59 -42
- data/lib/active_record/tasks/mysql_database_tasks.rb +32 -26
- data/lib/active_record/tasks/postgresql_database_tasks.rb +29 -9
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +20 -9
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +159 -67
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +2 -41
- data/lib/active_record/type/date_time.rb +2 -38
- data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
- data/lib/active_record/type/internal/abstract_json.rb +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +21 -14
- data/lib/active_record/type/time.rb +10 -16
- data/lib/active_record/type/type_map.rb +4 -4
- data/lib/active_record/type.rb +66 -17
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +10 -3
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +11 -12
- data/lib/active_record/validations/uniqueness.rb +29 -18
- data/lib/active_record/validations.rb +33 -32
- data/lib/active_record.rb +9 -2
- data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -6
- data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -7
- data/lib/rails/generators/active_record/migration.rb +7 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
- metadata +60 -34
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
- data/lib/active_record/serializers/xml_serializer.rb +0 -193
- data/lib/active_record/type/big_integer.rb +0 -13
- data/lib/active_record/type/binary.rb +0 -50
- data/lib/active_record/type/boolean.rb +0 -30
- data/lib/active_record/type/decimal.rb +0 -40
- data/lib/active_record/type/decimal_without_scale.rb +0 -11
- data/lib/active_record/type/decorator.rb +0 -14
- data/lib/active_record/type/float.rb +0 -19
- data/lib/active_record/type/integer.rb +0 -55
- data/lib/active_record/type/mutable.rb +0 -16
- data/lib/active_record/type/numeric.rb +0 -36
- data/lib/active_record/type/string.rb +0 -36
- data/lib/active_record/type/text.rb +0 -11
- data/lib/active_record/type/time_value.rb +0 -38
- data/lib/active_record/type/unsigned_integer.rb +0 -15
- data/lib/active_record/type/value.rb +0 -101
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/string/strip'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters
|
3
5
|
module PostgreSQL
|
@@ -5,33 +7,15 @@ module ActiveRecord
|
|
5
7
|
private
|
6
8
|
|
7
9
|
def visit_ColumnDefinition(o)
|
8
|
-
|
9
|
-
|
10
|
-
sql << " PRIMARY KEY "
|
11
|
-
add_column_options!(sql, column_options(o))
|
12
|
-
end
|
13
|
-
sql
|
10
|
+
o.sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale, o.array)
|
11
|
+
super
|
14
12
|
end
|
15
13
|
|
16
14
|
def add_column_options!(sql, options)
|
17
|
-
if options[:
|
18
|
-
sql <<
|
19
|
-
end
|
20
|
-
|
21
|
-
column = options.fetch(:column) { return super }
|
22
|
-
if column.type == :uuid && options[:default] =~ /\(\)/
|
23
|
-
sql << " DEFAULT #{options[:default]}"
|
24
|
-
else
|
25
|
-
super
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def type_for_column(column)
|
30
|
-
if column.array
|
31
|
-
@conn.lookup_cast_type("#{column.sql_type}[]")
|
32
|
-
else
|
33
|
-
super
|
15
|
+
if options[:collation]
|
16
|
+
sql << " COLLATE \"#{options[:collation]}\""
|
34
17
|
end
|
18
|
+
super
|
35
19
|
end
|
36
20
|
end
|
37
21
|
|
@@ -86,12 +70,24 @@ module ActiveRecord
|
|
86
70
|
execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
|
87
71
|
end
|
88
72
|
|
89
|
-
# Returns the list of all tables in the schema search path
|
73
|
+
# Returns the list of all tables in the schema search path.
|
90
74
|
def tables(name = nil)
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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))
|
95
91
|
SQL
|
96
92
|
end
|
97
93
|
|
@@ -99,10 +95,20 @@ module ActiveRecord
|
|
99
95
|
# If the schema is not specified as part of +name+ then it will only find tables within
|
100
96
|
# the current schema search path (regardless of permissions to access tables in other schemas)
|
101
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)
|
102
108
|
name = Utils.extract_schema_qualified_name(name.to_s)
|
103
109
|
return false unless name.identifier
|
104
110
|
|
105
|
-
|
111
|
+
select_value(<<-SQL, 'SCHEMA').to_i > 0
|
106
112
|
SELECT COUNT(*)
|
107
113
|
FROM pg_class c
|
108
114
|
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
@@ -112,124 +118,169 @@ module ActiveRecord
|
|
112
118
|
SQL
|
113
119
|
end
|
114
120
|
|
115
|
-
def
|
116
|
-
|
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
|
+
def drop_table(table_name, options = {}) # :nodoc:
|
146
|
+
execute "DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
|
117
147
|
end
|
118
148
|
|
119
149
|
# Returns true if schema exists.
|
120
150
|
def schema_exists?(name)
|
121
|
-
|
122
|
-
SELECT COUNT(*)
|
123
|
-
FROM pg_namespace
|
124
|
-
WHERE nspname = '#{name}'
|
125
|
-
SQL
|
151
|
+
select_value("SELECT COUNT(*) FROM pg_namespace WHERE nspname = '#{name}'", 'SCHEMA').to_i > 0
|
126
152
|
end
|
127
153
|
|
154
|
+
# Verifies existence of an index with a given name.
|
128
155
|
def index_name_exists?(table_name, index_name, default)
|
129
|
-
|
156
|
+
table = Utils.extract_schema_qualified_name(table_name.to_s)
|
157
|
+
index = Utils.extract_schema_qualified_name(index_name.to_s)
|
158
|
+
|
159
|
+
select_value(<<-SQL, 'SCHEMA').to_i > 0
|
130
160
|
SELECT COUNT(*)
|
131
161
|
FROM pg_class t
|
132
162
|
INNER JOIN pg_index d ON t.oid = d.indrelid
|
133
163
|
INNER JOIN pg_class i ON d.indexrelid = i.oid
|
164
|
+
LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
|
134
165
|
WHERE i.relkind = 'i'
|
135
|
-
AND i.relname = '#{
|
136
|
-
AND t.relname = '#{
|
137
|
-
AND
|
166
|
+
AND i.relname = '#{index.identifier}'
|
167
|
+
AND t.relname = '#{table.identifier}'
|
168
|
+
AND n.nspname = #{index.schema ? "'#{index.schema}'" : 'ANY (current_schemas(false))'}
|
138
169
|
SQL
|
139
170
|
end
|
140
171
|
|
141
172
|
# Returns an array of indexes for the given table.
|
142
173
|
def indexes(table_name, name = nil)
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
174
|
+
table = Utils.extract_schema_qualified_name(table_name.to_s)
|
175
|
+
|
176
|
+
result = query(<<-SQL, 'SCHEMA')
|
177
|
+
SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid,
|
178
|
+
pg_catalog.obj_description(i.oid, 'pg_class') AS comment,
|
179
|
+
(SELECT COUNT(*) FROM pg_opclass o
|
180
|
+
JOIN (SELECT unnest(string_to_array(d.indclass::text, ' '))::int oid) c
|
181
|
+
ON o.oid = c.oid WHERE o.opcdefault = 'f')
|
182
|
+
FROM pg_class t
|
183
|
+
INNER JOIN pg_index d ON t.oid = d.indrelid
|
184
|
+
INNER JOIN pg_class i ON d.indexrelid = i.oid
|
185
|
+
LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
|
186
|
+
WHERE i.relkind = 'i'
|
187
|
+
AND d.indisprimary = 'f'
|
188
|
+
AND t.relname = '#{table.identifier}'
|
189
|
+
AND n.nspname = #{table.schema ? "'#{table.schema}'" : 'ANY (current_schemas(false))'}
|
152
190
|
ORDER BY i.relname
|
153
191
|
SQL
|
154
192
|
|
155
193
|
result.map do |row|
|
156
194
|
index_name = row[0]
|
157
|
-
unique = row[1]
|
158
|
-
indkey = row[2].split(" ")
|
195
|
+
unique = row[1]
|
196
|
+
indkey = row[2].split(" ").map(&:to_i)
|
159
197
|
inddef = row[3]
|
160
198
|
oid = row[4]
|
199
|
+
comment = row[5]
|
200
|
+
opclass = row[6]
|
161
201
|
|
162
|
-
|
163
|
-
SELECT a.attnum, a.attname
|
164
|
-
FROM pg_attribute a
|
165
|
-
WHERE a.attrelid = #{oid}
|
166
|
-
AND a.attnum IN (#{indkey.join(",")})
|
167
|
-
SQL
|
202
|
+
using, expressions, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: WHERE (.+))?\z/).flatten
|
168
203
|
|
169
|
-
|
204
|
+
if indkey.include?(0) || opclass > 0
|
205
|
+
columns = expressions
|
206
|
+
else
|
207
|
+
columns = Hash[query(<<-SQL.strip_heredoc, "SCHEMA")].values_at(*indkey).compact
|
208
|
+
SELECT a.attnum, a.attname
|
209
|
+
FROM pg_attribute a
|
210
|
+
WHERE a.attrelid = #{oid}
|
211
|
+
AND a.attnum IN (#{indkey.join(",")})
|
212
|
+
SQL
|
170
213
|
|
171
|
-
unless column_names.empty?
|
172
214
|
# add info on sort order for columns (only desc order is explicitly specified, asc is the default)
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
using = inddef.scan(/USING (.+?) /).flatten[0].to_sym
|
177
|
-
|
178
|
-
IndexDefinition.new(table_name, index_name, unique, column_names, [], orders, where, nil, using)
|
215
|
+
orders = Hash[
|
216
|
+
expressions.scan(/(\w+) DESC/).flatten.map { |order_column| [order_column, :desc] }
|
217
|
+
]
|
179
218
|
end
|
219
|
+
|
220
|
+
IndexDefinition.new(table_name, index_name, unique, columns, [], orders, where, nil, using.to_sym, comment.presence)
|
180
221
|
end.compact
|
181
222
|
end
|
182
223
|
|
183
224
|
# Returns the list of all column definitions for a table.
|
184
|
-
def columns(table_name)
|
185
|
-
|
186
|
-
column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod|
|
187
|
-
oid =
|
188
|
-
|
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)
|
189
232
|
default_function = extract_default_function(default_value, default)
|
190
|
-
new_column(column_name, default_value,
|
233
|
+
new_column(column_name, default_value, type_metadata, !notnull, table_name, default_function, collation, comment: comment.presence)
|
191
234
|
end
|
192
235
|
end
|
193
236
|
|
194
|
-
def new_column(
|
195
|
-
PostgreSQLColumn.new(
|
237
|
+
def new_column(*args) # :nodoc:
|
238
|
+
PostgreSQLColumn.new(*args)
|
239
|
+
end
|
240
|
+
|
241
|
+
# Returns a comment stored in database for given table
|
242
|
+
def table_comment(table_name) # :nodoc:
|
243
|
+
name = Utils.extract_schema_qualified_name(table_name.to_s)
|
244
|
+
if name.identifier
|
245
|
+
select_value(<<-SQL.strip_heredoc, 'SCHEMA')
|
246
|
+
SELECT pg_catalog.obj_description(c.oid, 'pg_class')
|
247
|
+
FROM pg_catalog.pg_class c
|
248
|
+
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
249
|
+
WHERE c.relname = #{quote(name.identifier)}
|
250
|
+
AND c.relkind IN ('r') -- (r)elation/table
|
251
|
+
AND n.nspname = #{name.schema ? quote(name.schema) : 'ANY (current_schemas(false))'}
|
252
|
+
SQL
|
253
|
+
end
|
196
254
|
end
|
197
255
|
|
198
256
|
# Returns the current database name.
|
199
257
|
def current_database
|
200
|
-
|
258
|
+
select_value('select current_database()', 'SCHEMA')
|
201
259
|
end
|
202
260
|
|
203
261
|
# Returns the current schema name.
|
204
262
|
def current_schema
|
205
|
-
|
263
|
+
select_value('SELECT current_schema', 'SCHEMA')
|
206
264
|
end
|
207
265
|
|
208
266
|
# Returns the current database encoding format.
|
209
267
|
def encoding
|
210
|
-
|
211
|
-
SELECT pg_encoding_to_char(pg_database.encoding) FROM pg_database
|
212
|
-
WHERE pg_database.datname LIKE '#{current_database}'
|
213
|
-
end_sql
|
268
|
+
select_value("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA')
|
214
269
|
end
|
215
270
|
|
216
271
|
# Returns the current database collation.
|
217
272
|
def collation
|
218
|
-
|
219
|
-
SELECT pg_database.datcollate FROM pg_database WHERE pg_database.datname LIKE '#{current_database}'
|
220
|
-
end_sql
|
273
|
+
select_value("SELECT datcollate FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA')
|
221
274
|
end
|
222
275
|
|
223
276
|
# Returns the current database ctype.
|
224
277
|
def ctype
|
225
|
-
|
226
|
-
SELECT pg_database.datctype FROM pg_database WHERE pg_database.datname LIKE '#{current_database}'
|
227
|
-
end_sql
|
278
|
+
select_value("SELECT datctype FROM pg_database WHERE datname LIKE '#{current_database}'", 'SCHEMA')
|
228
279
|
end
|
229
280
|
|
230
281
|
# Returns an array of schema names.
|
231
282
|
def schema_names
|
232
|
-
|
283
|
+
select_values(<<-SQL, 'SCHEMA')
|
233
284
|
SELECT nspname
|
234
285
|
FROM pg_namespace
|
235
286
|
WHERE nspname !~ '^pg_.*'
|
@@ -240,12 +291,12 @@ module ActiveRecord
|
|
240
291
|
|
241
292
|
# Creates a schema for the given schema name.
|
242
293
|
def create_schema schema_name
|
243
|
-
execute "CREATE SCHEMA #{schema_name}"
|
294
|
+
execute "CREATE SCHEMA #{quote_schema_name(schema_name)}"
|
244
295
|
end
|
245
296
|
|
246
297
|
# Drops the schema for the given schema name.
|
247
|
-
def drop_schema
|
248
|
-
execute "DROP SCHEMA #{schema_name} CASCADE"
|
298
|
+
def drop_schema(schema_name, options = {})
|
299
|
+
execute "DROP SCHEMA#{' IF EXISTS' if options[:if_exists]} #{quote_schema_name(schema_name)} CASCADE"
|
249
300
|
end
|
250
301
|
|
251
302
|
# Sets the schema search path to a string of comma-separated schema names.
|
@@ -262,12 +313,12 @@ module ActiveRecord
|
|
262
313
|
|
263
314
|
# Returns the active schema search path.
|
264
315
|
def schema_search_path
|
265
|
-
@schema_search_path ||=
|
316
|
+
@schema_search_path ||= select_value('SHOW search_path', 'SCHEMA')
|
266
317
|
end
|
267
318
|
|
268
319
|
# Returns the current client message level.
|
269
320
|
def client_min_messages
|
270
|
-
|
321
|
+
select_value('SHOW client_min_messages', 'SCHEMA')
|
271
322
|
end
|
272
323
|
|
273
324
|
# Set the client message level.
|
@@ -285,10 +336,7 @@ module ActiveRecord
|
|
285
336
|
end
|
286
337
|
|
287
338
|
def serial_sequence(table, column)
|
288
|
-
|
289
|
-
SELECT pg_get_serial_sequence('#{table}', '#{column}')
|
290
|
-
eosql
|
291
|
-
result.rows.first.first
|
339
|
+
select_value("SELECT pg_get_serial_sequence('#{table}', '#{column}')", 'SCHEMA')
|
292
340
|
end
|
293
341
|
|
294
342
|
# Sets the sequence of a table's primary key to the specified value.
|
@@ -299,11 +347,9 @@ module ActiveRecord
|
|
299
347
|
if sequence
|
300
348
|
quoted_sequence = quote_table_name(sequence)
|
301
349
|
|
302
|
-
select_value
|
303
|
-
SELECT setval('#{quoted_sequence}', #{value})
|
304
|
-
end_sql
|
350
|
+
select_value("SELECT setval('#{quoted_sequence}', #{value})", 'SCHEMA')
|
305
351
|
else
|
306
|
-
@logger.warn "#{table} has primary key #{pk} with no default sequence" if @logger
|
352
|
+
@logger.warn "#{table} has primary key #{pk} with no default sequence." if @logger
|
307
353
|
end
|
308
354
|
end
|
309
355
|
end
|
@@ -318,13 +364,13 @@ module ActiveRecord
|
|
318
364
|
end
|
319
365
|
|
320
366
|
if @logger && pk && !sequence
|
321
|
-
@logger.warn "#{table} has primary key #{pk} with no default sequence"
|
367
|
+
@logger.warn "#{table} has primary key #{pk} with no default sequence."
|
322
368
|
end
|
323
369
|
|
324
370
|
if pk && sequence
|
325
371
|
quoted_sequence = quote_table_name(sequence)
|
326
372
|
|
327
|
-
select_value
|
373
|
+
select_value(<<-end_sql, 'SCHEMA')
|
328
374
|
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)
|
329
375
|
end_sql
|
330
376
|
end
|
@@ -384,17 +430,19 @@ module ActiveRecord
|
|
384
430
|
nil
|
385
431
|
end
|
386
432
|
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
433
|
+
def primary_keys(table_name) # :nodoc:
|
434
|
+
select_values(<<-SQL.strip_heredoc, 'SCHEMA')
|
435
|
+
WITH pk_constraint AS (
|
436
|
+
SELECT conrelid, unnest(conkey) AS connum FROM pg_constraint
|
437
|
+
WHERE contype = 'p'
|
438
|
+
AND conrelid = '#{quote_table_name(table_name)}'::regclass
|
439
|
+
), cons AS (
|
440
|
+
SELECT conrelid, connum, row_number() OVER() AS rownum FROM pk_constraint
|
441
|
+
)
|
442
|
+
SELECT attr.attname FROM pg_attribute attr
|
443
|
+
INNER JOIN cons ON attr.attrelid = cons.conrelid AND attr.attnum = cons.connum
|
444
|
+
ORDER BY cons.rownum
|
445
|
+
SQL
|
398
446
|
end
|
399
447
|
|
400
448
|
# Renames a table.
|
@@ -411,82 +459,122 @@ module ActiveRecord
|
|
411
459
|
new_seq = "#{new_name}_#{pk}_seq"
|
412
460
|
idx = "#{table_name}_pkey"
|
413
461
|
new_idx = "#{new_name}_pkey"
|
414
|
-
execute "ALTER TABLE #{
|
462
|
+
execute "ALTER TABLE #{seq.quoted} RENAME TO #{quote_table_name(new_seq)}"
|
415
463
|
execute "ALTER INDEX #{quote_table_name(idx)} RENAME TO #{quote_table_name(new_idx)}"
|
416
464
|
end
|
417
465
|
|
418
466
|
rename_table_indexes(table_name, new_name)
|
419
467
|
end
|
420
468
|
|
421
|
-
|
422
|
-
# See TableDefinition#column for details of the options you can use.
|
423
|
-
def add_column(table_name, column_name, type, options = {})
|
469
|
+
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
424
470
|
clear_cache!
|
425
471
|
super
|
472
|
+
change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
|
426
473
|
end
|
427
474
|
|
428
|
-
|
429
|
-
def change_column(table_name, column_name, type, options = {})
|
475
|
+
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
430
476
|
clear_cache!
|
431
477
|
quoted_table_name = quote_table_name(table_name)
|
432
|
-
|
433
|
-
sql_type
|
434
|
-
sql = "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{
|
435
|
-
|
436
|
-
|
437
|
-
|
478
|
+
quoted_column_name = quote_column_name(column_name)
|
479
|
+
sql_type = type_to_sql(type, options[:limit], options[:precision], options[:scale], options[:array])
|
480
|
+
sql = "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quoted_column_name} TYPE #{sql_type}"
|
481
|
+
if options[:collation]
|
482
|
+
sql << " COLLATE \"#{options[:collation]}\""
|
483
|
+
end
|
484
|
+
if options[:using]
|
485
|
+
sql << " USING #{options[:using]}"
|
486
|
+
elsif options[:cast_as]
|
487
|
+
cast_as_type = type_to_sql(options[:cast_as], options[:limit], options[:precision], options[:scale], options[:array])
|
488
|
+
sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
|
438
489
|
end
|
439
490
|
execute sql
|
440
491
|
|
441
492
|
change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
|
442
493
|
change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
|
494
|
+
change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
|
443
495
|
end
|
444
496
|
|
445
497
|
# Changes the default value of a table column.
|
446
|
-
def change_column_default(table_name, column_name,
|
498
|
+
def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
|
447
499
|
clear_cache!
|
448
500
|
column = column_for(table_name, column_name)
|
449
501
|
return unless column
|
450
502
|
|
503
|
+
default = extract_new_default_value(default_or_changes)
|
451
504
|
alter_column_query = "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} %s"
|
452
505
|
if default.nil?
|
453
506
|
# <tt>DEFAULT NULL</tt> results in the same behavior as <tt>DROP DEFAULT</tt>. However, PostgreSQL will
|
454
507
|
# cast the default to the columns type, which leaves us with a default like "default NULL::character varying".
|
455
508
|
execute alter_column_query % "DROP DEFAULT"
|
456
509
|
else
|
457
|
-
execute alter_column_query % "SET DEFAULT #{
|
510
|
+
execute alter_column_query % "SET DEFAULT #{quote_default_expression(default, column)}"
|
458
511
|
end
|
459
512
|
end
|
460
513
|
|
461
|
-
def change_column_null(table_name, column_name, null, default = nil)
|
514
|
+
def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
|
462
515
|
clear_cache!
|
463
516
|
unless null || default.nil?
|
464
517
|
column = column_for(table_name, column_name)
|
465
|
-
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{
|
518
|
+
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_expression(default, column)} WHERE #{quote_column_name(column_name)} IS NULL") if column
|
466
519
|
end
|
467
520
|
execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
|
468
521
|
end
|
469
522
|
|
523
|
+
# Adds comment for given table column or drops it if +comment+ is a +nil+
|
524
|
+
def change_column_comment(table_name, column_name, comment) # :nodoc:
|
525
|
+
clear_cache!
|
526
|
+
execute "COMMENT ON COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column_name)} IS #{quote(comment)}"
|
527
|
+
end
|
528
|
+
|
529
|
+
# Adds comment for given table or drops it if +comment+ is a +nil+
|
530
|
+
def change_table_comment(table_name, comment) # :nodoc:
|
531
|
+
clear_cache!
|
532
|
+
execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS #{quote(comment)}"
|
533
|
+
end
|
534
|
+
|
470
535
|
# Renames a column in a table.
|
471
|
-
def rename_column(table_name, column_name, new_column_name)
|
536
|
+
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
472
537
|
clear_cache!
|
473
538
|
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME COLUMN #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
|
474
539
|
rename_column_indexes(table_name, column_name, new_column_name)
|
475
540
|
end
|
476
541
|
|
477
542
|
def add_index(table_name, column_name, options = {}) #:nodoc:
|
478
|
-
index_name, index_type, index_columns, index_options, index_algorithm, index_using = add_index_options(table_name, column_name, options)
|
479
|
-
execute
|
543
|
+
index_name, index_type, index_columns, index_options, index_algorithm, index_using, comment = add_index_options(table_name, column_name, options)
|
544
|
+
execute("CREATE #{index_type} INDEX #{index_algorithm} #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{index_using} (#{index_columns})#{index_options}").tap do
|
545
|
+
execute "COMMENT ON INDEX #{quote_column_name(index_name)} IS #{quote(comment)}" if comment
|
546
|
+
end
|
480
547
|
end
|
481
548
|
|
482
|
-
def remove_index
|
483
|
-
|
549
|
+
def remove_index(table_name, options = {}) #:nodoc:
|
550
|
+
table = Utils.extract_schema_qualified_name(table_name.to_s)
|
551
|
+
|
552
|
+
if options.is_a?(Hash) && options.key?(:name)
|
553
|
+
provided_index = Utils.extract_schema_qualified_name(options[:name].to_s)
|
554
|
+
|
555
|
+
options[:name] = provided_index.identifier
|
556
|
+
table = PostgreSQL::Name.new(provided_index.schema, table.identifier) unless table.schema.present?
|
557
|
+
|
558
|
+
if provided_index.schema.present? && table.schema != provided_index.schema
|
559
|
+
raise ArgumentError.new("Index schema '#{provided_index.schema}' does not match table schema '#{table.schema}'")
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
index_to_remove = PostgreSQL::Name.new(table.schema, index_name_for_remove(table.to_s, options))
|
564
|
+
algorithm =
|
565
|
+
if options.is_a?(Hash) && options.key?(:algorithm)
|
566
|
+
index_algorithms.fetch(options[:algorithm]) do
|
567
|
+
raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}")
|
568
|
+
end
|
569
|
+
end
|
570
|
+
execute "DROP INDEX #{algorithm} #{quote_table_name(index_to_remove)}"
|
484
571
|
end
|
485
572
|
|
573
|
+
# Renames an index of a table. Raises error if length of new
|
574
|
+
# index name is greater than allowed limit.
|
486
575
|
def rename_index(table_name, old_name, new_name)
|
487
|
-
|
488
|
-
|
489
|
-
end
|
576
|
+
validate_index_length!(table_name, new_name)
|
577
|
+
|
490
578
|
execute "ALTER INDEX #{quote_column_name(old_name)} RENAME TO #{quote_table_name(new_name)}"
|
491
579
|
end
|
492
580
|
|
@@ -532,41 +620,35 @@ module ActiveRecord
|
|
532
620
|
end
|
533
621
|
|
534
622
|
# Maps logical Rails types to PostgreSQL-specific data types.
|
535
|
-
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
536
|
-
case type.to_s
|
623
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil, array = nil)
|
624
|
+
sql = case type.to_s
|
537
625
|
when 'binary'
|
538
626
|
# PostgreSQL doesn't support limits on binary (bytea) columns.
|
539
|
-
# The hard limit is
|
627
|
+
# The hard limit is 1GB, because of a 32-bit size field, and TOAST.
|
540
628
|
case limit
|
541
629
|
when nil, 0..0x3fffffff; super(type)
|
542
630
|
else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
|
543
631
|
end
|
544
632
|
when 'text'
|
545
633
|
# PostgreSQL doesn't support limits on text columns.
|
546
|
-
# The hard limit is
|
634
|
+
# The hard limit is 1GB, according to section 8.3 in the manual.
|
547
635
|
case limit
|
548
636
|
when nil, 0..0x3fffffff; super(type)
|
549
637
|
else raise(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.")
|
550
638
|
end
|
551
639
|
when 'integer'
|
552
|
-
return 'integer' unless limit
|
553
|
-
|
554
640
|
case limit
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
end
|
560
|
-
when 'datetime'
|
561
|
-
return super unless precision
|
562
|
-
|
563
|
-
case precision
|
564
|
-
when 0..6; "timestamp(#{precision})"
|
565
|
-
else raise(ActiveRecordError, "No timestamp type has precision of #{precision}. The allowed range of precision is from 0 to 6")
|
641
|
+
when 1, 2; 'smallint'
|
642
|
+
when nil, 3, 4; 'integer'
|
643
|
+
when 5..8; 'bigint'
|
644
|
+
else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead.")
|
566
645
|
end
|
567
646
|
else
|
568
|
-
super
|
647
|
+
super(type, limit, precision, scale)
|
569
648
|
end
|
649
|
+
|
650
|
+
sql << '[]' if array && type != :primary_key
|
651
|
+
sql
|
570
652
|
end
|
571
653
|
|
572
654
|
# PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
|
@@ -582,6 +664,18 @@ module ActiveRecord
|
|
582
664
|
|
583
665
|
[super, *order_columns].join(', ')
|
584
666
|
end
|
667
|
+
|
668
|
+
def fetch_type_metadata(column_name, sql_type, oid, fmod)
|
669
|
+
cast_type = get_oid_type(oid, fmod, column_name, sql_type)
|
670
|
+
simple_type = SqlTypeMetadata.new(
|
671
|
+
sql_type: sql_type,
|
672
|
+
type: cast_type.type,
|
673
|
+
limit: cast_type.limit,
|
674
|
+
precision: cast_type.precision,
|
675
|
+
scale: cast_type.scale,
|
676
|
+
)
|
677
|
+
PostgreSQLTypeMetadata.new(simple_type, oid: oid, fmod: fmod)
|
678
|
+
end
|
585
679
|
end
|
586
680
|
end
|
587
681
|
end
|