Skip to content

Commit d4df3d5

Browse files
authored
Merge pull request rails#50475 from waymondo/postgres-partition-options
support dumping PostgreSQL inheritance & partitioning options to `schema.rb`
2 parents c3f5eba + fba7ef0 commit d4df3d5

File tree

5 files changed

+142
-2
lines changed

5 files changed

+142
-2
lines changed

activerecord/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
* Add support for dumping table inheritance and native partitioning table definitions for PostgeSQL adapter
2+
3+
*Justin Talbott*
4+
15
* Deserialize database values before decryption
26

37
PostgreSQL binary values (`ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Bytea`)

activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,23 @@ def indexes(table_name) # :nodoc:
152152
end
153153

154154
def table_options(table_name) # :nodoc:
155-
if comment = table_comment(table_name)
156-
{ comment: comment }
155+
options = {}
156+
157+
comment = table_comment(table_name)
158+
159+
options[:comment] = comment if comment
160+
161+
inherited_table_names = inherited_table_names(table_name).presence
162+
163+
options[:options] = "INHERITS (#{inherited_table_names.join(", ")})" if inherited_table_names
164+
165+
if !options[:options] && supports_native_partitioning?
166+
partition_definition = table_partition_definition(table_name)
167+
168+
options[:options] = "PARTITION BY #{partition_definition}" if partition_definition
157169
end
170+
171+
options
158172
end
159173

160174
# Returns a comment stored in database for given table
@@ -172,6 +186,36 @@ def table_comment(table_name) # :nodoc:
172186
end
173187
end
174188

189+
# Returns the partition definition of a given table
190+
def table_partition_definition(table_name) # :nodoc:
191+
scope = quoted_scope(table_name, type: "BASE TABLE")
192+
193+
query_value(<<~SQL, "SCHEMA")
194+
SELECT pg_catalog.pg_get_partkeydef(c.oid)
195+
FROM pg_catalog.pg_class c
196+
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
197+
WHERE c.relname = #{scope[:name]}
198+
AND c.relkind IN (#{scope[:type]})
199+
AND n.nspname = #{scope[:schema]}
200+
SQL
201+
end
202+
203+
# Returns the inherited table name of a given table
204+
def inherited_table_names(table_name) # :nodoc:
205+
scope = quoted_scope(table_name, type: "BASE TABLE")
206+
207+
query_values(<<~SQL, "SCHEMA")
208+
SELECT parent.relname
209+
FROM pg_catalog.pg_inherits i
210+
JOIN pg_catalog.pg_class child ON i.inhrelid = child.oid
211+
JOIN pg_catalog.pg_class parent ON i.inhparent = parent.oid
212+
LEFT JOIN pg_namespace n ON n.oid = child.relnamespace
213+
WHERE child.relname = #{scope[:name]}
214+
AND child.relkind IN (#{scope[:type]})
215+
AND n.nspname = #{scope[:schema]}
216+
SQL
217+
end
218+
175219
# Returns the current database name.
176220
def current_database
177221
query_value("SELECT current_database()", "SCHEMA")

activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,10 @@ def supports_nulls_not_distinct?
284284
database_version >= 15_00_00 # >= 15.0
285285
end
286286

287+
def supports_native_partitioning? # :nodoc:
288+
database_version >= 10_00_00 # >= 10.0
289+
end
290+
287291
def index_algorithms
288292
{ concurrently: "CONCURRENTLY" }
289293
end

activerecord/test/cases/adapters/postgresql/schema_test.rb

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,3 +861,90 @@ def test_nulls_not_set_is_dumped
861861
assert_no_match(/nulls_not_distinct/, output)
862862
end
863863
end
864+
865+
class SchemaCreateTableOptionsTest < ActiveRecord::PostgreSQLTestCase
866+
include SchemaDumpingHelper
867+
868+
setup do
869+
@connection = ActiveRecord::Base.connection
870+
end
871+
872+
teardown do
873+
@connection.drop_table "trains", if_exists: true
874+
@connection.drop_table "transportation_modes", if_exists: true
875+
@connection.drop_table "vehicles", if_exists: true
876+
end
877+
878+
def test_list_partition_options_is_dumped
879+
skip("current adapter doesn't support native partitioning") unless supports_native_partitioning?
880+
881+
options = "PARTITION BY LIST (kind)"
882+
883+
@connection.create_table "trains", id: false, options: options do |t|
884+
t.string :name
885+
t.string :kind
886+
end
887+
888+
output = dump_table_schema "trains"
889+
890+
assert_match("options: \"#{options}\"", output)
891+
end
892+
893+
def test_range_partition_options_is_dumped
894+
skip("current adapter doesn't support native partitioning") unless supports_native_partitioning?
895+
896+
options = "PARTITION BY RANGE (created_at)"
897+
898+
@connection.create_table "trains", id: false, options: options do |t|
899+
t.string :name
900+
t.datetime :created_at, null: false
901+
end
902+
903+
output = dump_table_schema "trains"
904+
905+
assert_match("options: \"#{options}\"", output)
906+
end
907+
908+
def test_inherited_table_options_is_dumped
909+
@connection.create_table "transportation_modes" do |t|
910+
t.string :name
911+
t.string :kind
912+
end
913+
914+
options = "INHERITS (transportation_modes)"
915+
916+
@connection.create_table "trains", options: options
917+
918+
output = dump_table_schema "trains"
919+
920+
assert_match("options: \"#{options}\"", output)
921+
end
922+
923+
def test_multiple_inherited_table_options_is_dumped
924+
@connection.create_table "vehicles" do |t|
925+
t.string :name
926+
end
927+
928+
@connection.create_table "transportation_modes" do |t|
929+
t.string :kind
930+
end
931+
932+
options = "INHERITS (transportation_modes, vehicles)"
933+
934+
@connection.create_table "trains", options: options
935+
936+
output = dump_table_schema "trains"
937+
938+
assert_match("options: \"#{options}\"", output)
939+
end
940+
941+
def test_no_partition_options_are_dumped
942+
@connection.create_table "trains" do |t|
943+
t.string :name
944+
end
945+
946+
output = dump_table_schema "trains"
947+
948+
assert_no_match("options:", output)
949+
end
950+
end

activerecord/test/support/adapter_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def supports_text_column_with_default?
6060
supports_nulls_not_distinct?
6161
supports_identity_columns?
6262
supports_virtual_columns?
63+
supports_native_partitioning?
6364
].each do |method_name|
6465
define_method method_name do
6566
ActiveRecord::Base.lease_connection.public_send(method_name)

0 commit comments

Comments
 (0)