pg, reset_pk_sequence!
respects schemas. Closes #14719.
This commit is contained in:
parent
7b8d95d58f
commit
290de901dd
@ -1,3 +1,7 @@
|
||||
* PostgreSQL `reset_pk_sequence!` respects schemas. Fixes #14719.
|
||||
|
||||
*Yves Senn*
|
||||
|
||||
* Keep PostgreSQL `hstore` and `json` attributes as `Hash` in `@attributes`.
|
||||
Fixes duplication in combination with `store_accessor`.
|
||||
|
||||
|
@ -312,17 +312,19 @@ def pk_and_sequence_for(table) #:nodoc:
|
||||
# First try looking for a sequence with a dependency on the
|
||||
# given table's primary key.
|
||||
result = query(<<-end_sql, 'SCHEMA')[0]
|
||||
SELECT attr.attname, seq.relname
|
||||
SELECT attr.attname, nsp.nspname, seq.relname
|
||||
FROM pg_class seq,
|
||||
pg_attribute attr,
|
||||
pg_depend dep,
|
||||
pg_constraint cons
|
||||
pg_constraint cons,
|
||||
pg_namespace nsp
|
||||
WHERE seq.oid = dep.objid
|
||||
AND seq.relkind = 'S'
|
||||
AND attr.attrelid = dep.refobjid
|
||||
AND attr.attnum = dep.refobjsubid
|
||||
AND attr.attrelid = cons.conrelid
|
||||
AND attr.attnum = cons.conkey[1]
|
||||
AND seq.relnamespace = nsp.oid
|
||||
AND cons.contype = 'p'
|
||||
AND dep.classid = 'pg_class'::regclass
|
||||
AND dep.refobjid = '#{quote_table_name(table)}'::regclass
|
||||
@ -330,7 +332,7 @@ def pk_and_sequence_for(table) #:nodoc:
|
||||
|
||||
if result.nil? or result.empty?
|
||||
result = query(<<-end_sql, 'SCHEMA')[0]
|
||||
SELECT attr.attname,
|
||||
SELECT attr.attname, nsp.nspname,
|
||||
CASE
|
||||
WHEN pg_get_expr(def.adbin, def.adrelid) !~* 'nextval' THEN NULL
|
||||
WHEN split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2) ~ '.' THEN
|
||||
@ -342,13 +344,19 @@ def pk_and_sequence_for(table) #:nodoc:
|
||||
JOIN pg_attribute attr ON (t.oid = attrelid)
|
||||
JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
|
||||
JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
|
||||
JOIN pg_namespace nsp ON (t.relnamespace = nsp.oid)
|
||||
WHERE t.oid = '#{quote_table_name(table)}'::regclass
|
||||
AND cons.contype = 'p'
|
||||
AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval|uuid_generate'
|
||||
end_sql
|
||||
end
|
||||
|
||||
[result.first, result.last]
|
||||
pk = result.shift
|
||||
if result.last
|
||||
[pk, PostgreSQL::Name.new(*result)]
|
||||
else
|
||||
[pk, nil]
|
||||
end
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
@ -376,7 +384,7 @@ def rename_table(table_name, new_name)
|
||||
clear_cache!
|
||||
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
|
||||
pk, seq = pk_and_sequence_for(new_name)
|
||||
if seq == "#{table_name}_#{pk}_seq"
|
||||
if seq.identifier == "#{table_name}_#{pk}_seq"
|
||||
new_seq = "#{new_name}_#{pk}_seq"
|
||||
execute "ALTER TABLE #{quote_table_name(seq)} RENAME TO #{quote_table_name(new_seq)}"
|
||||
end
|
||||
|
@ -153,7 +153,8 @@ def test_pk_and_sequence_for
|
||||
with_example_table do
|
||||
pk, seq = @connection.pk_and_sequence_for('ex')
|
||||
assert_equal 'id', pk
|
||||
assert_equal @connection.default_sequence_name('ex', 'id'), seq
|
||||
expected = PostgreSQL::Name.new("public", @connection.default_sequence_name('ex', 'id'))
|
||||
assert_equal expected, seq
|
||||
end
|
||||
end
|
||||
|
||||
@ -161,7 +162,8 @@ def test_pk_and_sequence_for_with_non_standard_primary_key
|
||||
with_example_table 'code serial primary key' do
|
||||
pk, seq = @connection.pk_and_sequence_for('ex')
|
||||
assert_equal 'code', pk
|
||||
assert_equal @connection.default_sequence_name('ex', 'code'), seq
|
||||
expected = PostgreSQL::Name.new("public", @connection.default_sequence_name('ex', 'code'))
|
||||
assert_equal expected, seq
|
||||
end
|
||||
end
|
||||
|
||||
@ -216,7 +218,7 @@ def test_pk_and_sequence_for_with_collision_pg_class_oid
|
||||
)
|
||||
|
||||
seq = @connection.pk_and_sequence_for('ex').last
|
||||
assert_equal 'ex_id_seq', seq
|
||||
assert_equal PostgreSQL::Name.new("public", "ex_id_seq"), seq
|
||||
|
||||
@connection.exec_query(
|
||||
"DELETE FROM pg_depend WHERE objid = 'ex2_id_seq'::regclass AND refobjid = 'ex'::regclass AND deptype = 'a'"
|
||||
|
@ -331,14 +331,15 @@ def test_primary_key_raises_error_if_table_not_found_on_schema_search_path
|
||||
end
|
||||
|
||||
def test_pk_and_sequence_for_with_schema_specified
|
||||
pg_name = ActiveRecord::ConnectionAdapters::PostgreSQL::Name
|
||||
[
|
||||
%("#{SCHEMA_NAME}"."#{PK_TABLE_NAME}"),
|
||||
%("#{SCHEMA_NAME}"."#{UNMATCHED_PK_TABLE_NAME}")
|
||||
].each do |given|
|
||||
pk, seq = @connection.pk_and_sequence_for(given)
|
||||
assert_equal 'id', pk, "primary key should be found when table referenced as #{given}"
|
||||
assert_equal "#{PK_TABLE_NAME}_id_seq", seq, "sequence name should be found when table referenced as #{given}" if given == %("#{SCHEMA_NAME}"."#{PK_TABLE_NAME}")
|
||||
assert_equal "#{UNMATCHED_SEQUENCE_NAME}", seq, "sequence name should be found when table referenced as #{given}" if given == %("#{SCHEMA_NAME}"."#{UNMATCHED_PK_TABLE_NAME}")
|
||||
assert_equal pg_name.new(SCHEMA_NAME, "#{PK_TABLE_NAME}_id_seq"), seq, "sequence name should be found when table referenced as #{given}" if given == %("#{SCHEMA_NAME}"."#{PK_TABLE_NAME}")
|
||||
assert_equal pg_name.new(SCHEMA_NAME, UNMATCHED_SEQUENCE_NAME), seq, "sequence name should be found when table referenced as #{given}" if given == %("#{SCHEMA_NAME}"."#{UNMATCHED_PK_TABLE_NAME}")
|
||||
end
|
||||
end
|
||||
|
||||
@ -378,6 +379,14 @@ def test_schema_exists?
|
||||
end
|
||||
end
|
||||
|
||||
def test_reset_pk_sequence
|
||||
sequence_name = "#{SCHEMA_NAME}.#{UNMATCHED_SEQUENCE_NAME}"
|
||||
@connection.execute "SELECT setval('#{sequence_name}', 123)"
|
||||
assert_equal "124", @connection.select_value("SELECT nextval('#{sequence_name}')")
|
||||
@connection.reset_pk_sequence!("#{SCHEMA_NAME}.#{UNMATCHED_PK_TABLE_NAME}")
|
||||
assert_equal "1", @connection.select_value("SELECT nextval('#{sequence_name}')")
|
||||
end
|
||||
|
||||
private
|
||||
def columns(table_name)
|
||||
@connection.send(:column_definitions, table_name).map do |name, type, default|
|
||||
|
@ -74,7 +74,7 @@ def test_rename_table_for_postgresql_should_also_rename_default_sequence
|
||||
|
||||
pk, seq = connection.pk_and_sequence_for('octopi')
|
||||
|
||||
assert_equal "octopi_#{pk}_seq", seq
|
||||
assert_equal ConnectionAdapters::PostgreSQL::Name.new("public", "octopi_#{pk}_seq"), seq
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user