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
|
* Deserialize database values before decryption
|
||||||
|
|
||||||
PostgreSQL binary values (`ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Bytea`)
|
PostgreSQL binary values (`ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Bytea`)
|
||||||
|
|
|
@ -152,9 +152,23 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def table_options(table_name) # :nodoc:
|
def table_options(table_name) # :nodoc:
|
||||||
if comment = table_comment(table_name)
|
options = {}
|
||||||
{ comment: comment }
|
|
||||||
|
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
|
end
|
||||||
|
|
||||||
|
options
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns a comment stored in database for given table
|
# Returns a comment stored in database for given table
|
||||||
|
@ -172,6 +186,36 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
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.
|
# Returns the current database name.
|
||||||
def current_database
|
def current_database
|
||||||
query_value("SELECT current_database()", "SCHEMA")
|
query_value("SELECT current_database()", "SCHEMA")
|
||||||
|
|
|
@ -284,6 +284,10 @@ module ActiveRecord
|
||||||
database_version >= 15_00_00 # >= 15.0
|
database_version >= 15_00_00 # >= 15.0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def supports_native_partitioning? # :nodoc:
|
||||||
|
database_version >= 10_00_00 # >= 10.0
|
||||||
|
end
|
||||||
|
|
||||||
def index_algorithms
|
def index_algorithms
|
||||||
{ concurrently: "CONCURRENTLY" }
|
{ concurrently: "CONCURRENTLY" }
|
||||||
end
|
end
|
||||||
|
|
|
@ -861,3 +861,90 @@ class SchemaIndexNullsNotDistinctTest < ActiveRecord::PostgreSQLTestCase
|
||||||
assert_no_match(/nulls_not_distinct/, output)
|
assert_no_match(/nulls_not_distinct/, output)
|
||||||
end
|
end
|
||||||
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_nulls_not_distinct?
|
||||||
supports_identity_columns?
|
supports_identity_columns?
|
||||||
supports_virtual_columns?
|
supports_virtual_columns?
|
||||||
|
supports_native_partitioning?
|
||||||
].each do |method_name|
|
].each do |method_name|
|
||||||
define_method method_name do
|
define_method method_name do
|
||||||
ActiveRecord::Base.lease_connection.public_send(method_name)
|
ActiveRecord::Base.lease_connection.public_send(method_name)
|
||||||
|
|
Loading…
Reference in New Issue