mirror of https://github.com/rails/rails
Merge pull request #50475 from waymondo/postgres-partition-options
support dumping PostgreSQL inheritance & partitioning options to `schema.rb`
This commit is contained in:
commit
d4df3d5f81
|
@ -1,3 +1,7 @@
|
|||
* Add support for dumping table inheritance and native partitioning table definitions for PostgeSQL adapter
|
||||
|
||||
*Justin Talbott*
|
||||
|
||||
* Deserialize database values before decryption
|
||||
|
||||
PostgreSQL binary values (`ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Bytea`)
|
||||
|
|
|
@ -152,9 +152,23 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def table_options(table_name) # :nodoc:
|
||||
if comment = table_comment(table_name)
|
||||
{ comment: comment }
|
||||
options = {}
|
||||
|
||||
comment = table_comment(table_name)
|
||||
|
||||
options[:comment] = comment if comment
|
||||
|
||||
inherited_table_names = inherited_table_names(table_name).presence
|
||||
|
||||
options[:options] = "INHERITS (#{inherited_table_names.join(", ")})" if inherited_table_names
|
||||
|
||||
if !options[:options] && supports_native_partitioning?
|
||||
partition_definition = table_partition_definition(table_name)
|
||||
|
||||
options[:options] = "PARTITION BY #{partition_definition}" if partition_definition
|
||||
end
|
||||
|
||||
options
|
||||
end
|
||||
|
||||
# Returns a comment stored in database for given table
|
||||
|
@ -172,6 +186,36 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
|
||||
# Returns the partition definition of a given table
|
||||
def table_partition_definition(table_name) # :nodoc:
|
||||
scope = quoted_scope(table_name, type: "BASE TABLE")
|
||||
|
||||
query_value(<<~SQL, "SCHEMA")
|
||||
SELECT pg_catalog.pg_get_partkeydef(c.oid)
|
||||
FROM pg_catalog.pg_class c
|
||||
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
||||
WHERE c.relname = #{scope[:name]}
|
||||
AND c.relkind IN (#{scope[:type]})
|
||||
AND n.nspname = #{scope[:schema]}
|
||||
SQL
|
||||
end
|
||||
|
||||
# Returns the inherited table name of a given table
|
||||
def inherited_table_names(table_name) # :nodoc:
|
||||
scope = quoted_scope(table_name, type: "BASE TABLE")
|
||||
|
||||
query_values(<<~SQL, "SCHEMA")
|
||||
SELECT parent.relname
|
||||
FROM pg_catalog.pg_inherits i
|
||||
JOIN pg_catalog.pg_class child ON i.inhrelid = child.oid
|
||||
JOIN pg_catalog.pg_class parent ON i.inhparent = parent.oid
|
||||
LEFT JOIN pg_namespace n ON n.oid = child.relnamespace
|
||||
WHERE child.relname = #{scope[:name]}
|
||||
AND child.relkind IN (#{scope[:type]})
|
||||
AND n.nspname = #{scope[:schema]}
|
||||
SQL
|
||||
end
|
||||
|
||||
# Returns the current database name.
|
||||
def current_database
|
||||
query_value("SELECT current_database()", "SCHEMA")
|
||||
|
|
|
@ -284,6 +284,10 @@ module ActiveRecord
|
|||
database_version >= 15_00_00 # >= 15.0
|
||||
end
|
||||
|
||||
def supports_native_partitioning? # :nodoc:
|
||||
database_version >= 10_00_00 # >= 10.0
|
||||
end
|
||||
|
||||
def index_algorithms
|
||||
{ concurrently: "CONCURRENTLY" }
|
||||
end
|
||||
|
|
|
@ -861,3 +861,90 @@ class SchemaIndexNullsNotDistinctTest < ActiveRecord::PostgreSQLTestCase
|
|||
assert_no_match(/nulls_not_distinct/, output)
|
||||
end
|
||||
end
|
||||
|
||||
class SchemaCreateTableOptionsTest < ActiveRecord::PostgreSQLTestCase
|
||||
include SchemaDumpingHelper
|
||||
|
||||
setup do
|
||||
@connection = ActiveRecord::Base.connection
|
||||
end
|
||||
|
||||
teardown do
|
||||
@connection.drop_table "trains", if_exists: true
|
||||
@connection.drop_table "transportation_modes", if_exists: true
|
||||
@connection.drop_table "vehicles", if_exists: true
|
||||
end
|
||||
|
||||
def test_list_partition_options_is_dumped
|
||||
skip("current adapter doesn't support native partitioning") unless supports_native_partitioning?
|
||||
|
||||
options = "PARTITION BY LIST (kind)"
|
||||
|
||||
@connection.create_table "trains", id: false, options: options do |t|
|
||||
t.string :name
|
||||
t.string :kind
|
||||
end
|
||||
|
||||
output = dump_table_schema "trains"
|
||||
|
||||
assert_match("options: \"#{options}\"", output)
|
||||
end
|
||||
|
||||
def test_range_partition_options_is_dumped
|
||||
skip("current adapter doesn't support native partitioning") unless supports_native_partitioning?
|
||||
|
||||
options = "PARTITION BY RANGE (created_at)"
|
||||
|
||||
@connection.create_table "trains", id: false, options: options do |t|
|
||||
t.string :name
|
||||
t.datetime :created_at, null: false
|
||||
end
|
||||
|
||||
output = dump_table_schema "trains"
|
||||
|
||||
assert_match("options: \"#{options}\"", output)
|
||||
end
|
||||
|
||||
def test_inherited_table_options_is_dumped
|
||||
@connection.create_table "transportation_modes" do |t|
|
||||
t.string :name
|
||||
t.string :kind
|
||||
end
|
||||
|
||||
options = "INHERITS (transportation_modes)"
|
||||
|
||||
@connection.create_table "trains", options: options
|
||||
|
||||
output = dump_table_schema "trains"
|
||||
|
||||
assert_match("options: \"#{options}\"", output)
|
||||
end
|
||||
|
||||
def test_multiple_inherited_table_options_is_dumped
|
||||
@connection.create_table "vehicles" do |t|
|
||||
t.string :name
|
||||
end
|
||||
|
||||
@connection.create_table "transportation_modes" do |t|
|
||||
t.string :kind
|
||||
end
|
||||
|
||||
options = "INHERITS (transportation_modes, vehicles)"
|
||||
|
||||
@connection.create_table "trains", options: options
|
||||
|
||||
output = dump_table_schema "trains"
|
||||
|
||||
assert_match("options: \"#{options}\"", output)
|
||||
end
|
||||
|
||||
def test_no_partition_options_are_dumped
|
||||
@connection.create_table "trains" do |t|
|
||||
t.string :name
|
||||
end
|
||||
|
||||
output = dump_table_schema "trains"
|
||||
|
||||
assert_no_match("options:", output)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -60,6 +60,7 @@ module AdapterHelper
|
|||
supports_nulls_not_distinct?
|
||||
supports_identity_columns?
|
||||
supports_virtual_columns?
|
||||
supports_native_partitioning?
|
||||
].each do |method_name|
|
||||
define_method method_name do
|
||||
ActiveRecord::Base.lease_connection.public_send(method_name)
|
||||
|
|
Loading…
Reference in New Issue