96 lines
3.6 KiB
Ruby
96 lines
3.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Database
|
|
module PartitioningHelpers
|
|
def expect_table_partitioned_by(table, columns, part_type: :range)
|
|
columns_with_part_type = columns.map { |c| [part_type.to_s, c] }
|
|
actual_columns = find_partitioned_columns(table)
|
|
|
|
expect(columns_with_part_type).to match_array(actual_columns)
|
|
end
|
|
|
|
def expect_range_partition_of(partition_name, table_name, min_value, max_value)
|
|
definition = find_partition_definition(partition_name, schema: Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA)
|
|
|
|
expect(definition).not_to be_nil
|
|
expect(definition['base_table']).to eq(table_name.to_s)
|
|
expect(definition['condition']).to eq("FOR VALUES FROM (#{min_value}) TO (#{max_value})")
|
|
end
|
|
|
|
def expect_total_partitions(table_name, count, schema: Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA)
|
|
partitions = find_partitions(table_name, schema: schema)
|
|
|
|
expect(partitions.size).to eq(count)
|
|
end
|
|
|
|
def expect_range_partitions_for(table_name, partitions)
|
|
partitions.each do |suffix, (min_value, max_value)|
|
|
partition_name = "#{table_name}_#{suffix}"
|
|
expect_range_partition_of(partition_name, table_name, min_value, max_value)
|
|
end
|
|
|
|
expect_total_partitions(table_name, partitions.size, schema: Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA)
|
|
end
|
|
|
|
def expect_hash_partition_of(partition_name, table_name, modulus, remainder)
|
|
definition = find_partition_definition(partition_name, schema: Gitlab::Database::STATIC_PARTITIONS_SCHEMA)
|
|
|
|
expect(definition).not_to be_nil
|
|
expect(definition['base_table']).to eq(table_name.to_s)
|
|
expect(definition['condition']).to eq("FOR VALUES WITH (modulus #{modulus}, remainder #{remainder})")
|
|
end
|
|
|
|
private
|
|
|
|
def find_partitioned_columns(table)
|
|
connection.select_rows(<<~SQL)
|
|
select
|
|
case partstrat
|
|
when 'l' then 'list'
|
|
when 'r' then 'range'
|
|
when 'h' then 'hash'
|
|
end as partstrat,
|
|
cols.column_name
|
|
from (
|
|
select partrelid, partstrat, unnest(partattrs) as col_pos
|
|
from pg_partitioned_table
|
|
) pg_part
|
|
inner join pg_class
|
|
on pg_part.partrelid = pg_class.oid
|
|
inner join information_schema.columns cols
|
|
on cols.table_name = pg_class.relname
|
|
and cols.ordinal_position = pg_part.col_pos
|
|
where pg_class.relname = '#{table}';
|
|
SQL
|
|
end
|
|
|
|
def find_partition_definition(partition, schema: )
|
|
connection.select_one(<<~SQL)
|
|
select
|
|
parent_class.relname as base_table,
|
|
pg_get_expr(pg_class.relpartbound, inhrelid) as condition
|
|
from pg_class
|
|
inner join pg_inherits i on pg_class.oid = inhrelid
|
|
inner join pg_class parent_class on parent_class.oid = inhparent
|
|
inner join pg_namespace ON pg_namespace.oid = pg_class.relnamespace
|
|
where pg_namespace.nspname = '#{schema}'
|
|
and pg_class.relname = '#{partition}'
|
|
and pg_class.relispartition
|
|
SQL
|
|
end
|
|
|
|
def find_partitions(partition, schema: Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA, conn: connection)
|
|
conn.select_rows(<<~SQL)
|
|
select
|
|
pg_class.relname
|
|
from pg_class
|
|
inner join pg_inherits i on pg_class.oid = inhrelid
|
|
inner join pg_class parent_class on parent_class.oid = inhparent
|
|
inner join pg_namespace ON pg_namespace.oid = pg_class.relnamespace
|
|
where pg_namespace.nspname = '#{schema}'
|
|
and parent_class.relname = '#{partition}'
|
|
and pg_class.relispartition
|
|
SQL
|
|
end
|
|
end
|
|
end
|