PostgreSQL 10 : Each sequence does not have `increment_by` column, need to use `pg_sequences` #28780
Comments
Do we even need to add |
$ psql -d test
psql (10devel)
Type "help" for help.
test=# create sequence test_seq;
CREATE SEQUENCE
test=# select * from pg_sequences;
schemaname | sequencename | sequenceowner | data_type | start_value | min_value | max_value | increment_by | cycle | cache_size | last_value
------------+--------------+---------------+-----------+-------------+-----------+---------------------+--------------+-------+------------+------------
public | test_seq | yahonda | bigint | 1 | 1 | 9223372036854775807 | 1 | f | 1 |
(1 row)
test=# select setval('test_seq', 100, false);
setval
--------
100
(1 row)
test=# select nextval('test_seq');
nextval
---------
100
(1 row)
test=#
$ ARCONN=postgresql bundle exec ruby -w -Itest test/cases/primary_keys_test.rb -n test_integer_key
/home/ubuntu/rails/activesupport/lib/active_support/core_ext/enumerable.rb:20: warning: method redefined; discarding old sum
Using postgresql
Run options: -n test_integer_key --seed 51286
# Running:
E
Finished in 0.101177s, 9.8837 runs/s, 29.6511 assertions/s.
1) Error:
PrimaryKeysTest#test_integer_key:
ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "topics_pkey"
DETAIL: Key (id)=(5) already exists.
: INSERT INTO "topics" ("title", "author_email_address", "written_on", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb:613:in `async_exec'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb:613:in `block (2 levels) in exec_no_cache'
/home/ubuntu/rails/activesupport/lib/active_support/dependencies/interlock.rb:46:in `block in permit_concurrent_loads'
/home/ubuntu/rails/activesupport/lib/active_support/concurrency/share_lock.rb:185:in `yield_shares'
/home/ubuntu/rails/activesupport/lib/active_support/dependencies/interlock.rb:45:in `permit_concurrent_loads'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb:612:in `block in exec_no_cache'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:580:in `block (2 levels) in log'
/usr/lib/ruby/2.4.0/monitor.rb:214:in `mon_synchronize'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:579:in `block in log'
/home/ubuntu/rails/activesupport/lib/active_support/notifications/instrumenter.rb:21:in `instrument'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:571:in `log'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb:611:in `exec_no_cache'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb:600:in `execute_and_clear'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb:103:in `exec_query'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:92:in `exec_insert'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb:137:in `exec_insert'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:123:in `insert'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:17:in `insert'
/home/ubuntu/rails/activerecord/lib/active_record/relation.rb:61:in `insert'
/home/ubuntu/rails/activerecord/lib/active_record/persistence.rb:578:in `_create_record'
/home/ubuntu/rails/activerecord/lib/active_record/counter_cache.rb:178:in `_create_record'
/home/ubuntu/rails/activerecord/lib/active_record/locking/optimistic.rb:76:in `_create_record'
/home/ubuntu/rails/activerecord/lib/active_record/attribute_methods/dirty.rb:296:in `_create_record'
/home/ubuntu/rails/activerecord/lib/active_record/callbacks.rb:340:in `block in _create_record'
/home/ubuntu/rails/activesupport/lib/active_support/callbacks.rb:131:in `run_callbacks'
/home/ubuntu/rails/activesupport/lib/active_support/callbacks.rb:825:in `_run_create_callbacks'
/home/ubuntu/rails/activerecord/lib/active_record/callbacks.rb:340:in `_create_record'
/home/ubuntu/rails/activerecord/lib/active_record/timestamp.rb:95:in `_create_record'
/home/ubuntu/rails/activerecord/lib/active_record/persistence.rb:555:in `create_or_update'
/home/ubuntu/rails/activerecord/lib/active_record/callbacks.rb:336:in `block in create_or_update'
/home/ubuntu/rails/activesupport/lib/active_support/callbacks.rb:131:in `run_callbacks'
/home/ubuntu/rails/activesupport/lib/active_support/callbacks.rb:825:in `_run_save_callbacks'
/home/ubuntu/rails/activerecord/lib/active_record/callbacks.rb:336:in `create_or_update'
/home/ubuntu/rails/activerecord/lib/active_record/persistence.rb:154:in `save!'
/home/ubuntu/rails/activerecord/lib/active_record/validations.rb:50:in `save!'
/home/ubuntu/rails/activerecord/lib/active_record/attribute_methods/dirty.rb:43:in `save!'
/home/ubuntu/rails/activerecord/lib/active_record/transactions.rb:313:in `block in save!'
/home/ubuntu/rails/activerecord/lib/active_record/transactions.rb:384:in `block in with_transaction_returning_status'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:225:in `block in transaction'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb:194:in `block in within_new_transaction'
/usr/lib/ruby/2.4.0/monitor.rb:214:in `mon_synchronize'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb:191:in `within_new_transaction'
/home/ubuntu/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:225:in `transaction'
/home/ubuntu/rails/activerecord/lib/active_record/transactions.rb:210:in `transaction'
/home/ubuntu/rails/activerecord/lib/active_record/transactions.rb:381:in `with_transaction_returning_status'
/home/ubuntu/rails/activerecord/lib/active_record/transactions.rb:313:in `save!'
/home/ubuntu/rails/activerecord/lib/active_record/suppressor.rb:46:in `save!'
test/cases/primary_keys_test.rb:49:in `block in test_integer_key'
/home/ubuntu/rails/activesupport/lib/active_support/testing/assertions.rb:30:in `assert_nothing_raised'
test/cases/primary_keys_test.rb:49:in `test_integer_key'
1 runs, 3 assertions, 0 failures, 1 errors, 0 skips
$ Then replacing $ ARCONN=postgresql bundle exec ruby -w -Itest test/cases/fixtures_test.rb -n test_resets_to_min_pk_with_default_pk_and_sequence
/home/ubuntu/rails/activesupport/lib/active_support/core_ext/enumerable.rb:20: warning: method redefined; discarding old sum
Using postgresql
Run options: -n test_resets_to_min_pk_with_default_pk_and_sequence --seed 54529
# Running:
F
Finished in 0.078813s, 12.6883 runs/s, 12.6883 assertions/s.
1) Failure:
FixturesResetPkSequenceTest#test_resets_to_min_pk_with_default_pk_and_sequence [test/cases/fixtures_test.rb:392]:
Sequence reset for accounts failed..
Expected: 1
Actual: 2
1 runs, 1 assertions, 1 failures, 0 errors, 0 skips
$ |
For references:
|
Also, we will need to address the later part of this sql statement. activerecord_unittest=# SELECT min_value FROM "public"."topics_id_seq";
ERROR: column "min_value" does not exist
LINE 1: SELECT min_value FROM "public"."topics_id_seq";
^
activerecord_unittest=# |
@yahonda could we not set the third argument based on whether the table is empty or not? |
…min_value` Addresses rails#28780 - Each sequence does not know `increment_by` or `min_value` since PostgreSQL 10. A new system catalog `pg_sequences` knows both. postgres/postgres@1753b1b - Since `pg_sequences` does not exist PostgreSQL 9.6 or earlier version This commit addresses by removing `increment_by` or `min_value` - `setval` 3rd argument needs to set to `false` only when the table has no rows to avoid `nextval(<sequence_name>)` returns 2 where 1 is expected. - Replaced `min_value` with `1` since it is necessary only when the table has no rows. If someone wants to reset sequence to non 1 when table has no rows new pull requests/commits required.
Thanks for the suggestion. I have opened #28789 which supports both PostgreSQL 10 and PostgreSQL 9.x. |
Another fix for rails#28780 based on discussions at rails#28789 - In PostgreSQL 10 each sequence does not know its `min_value`. A new system catalog `pg_sequence` shows it as `seqmin`. Refer postgres/postgres@1753b1b - `setval` 3rd argument needs to set to `false` only when the table has no rows to avoid `nextval(<sequence_name>)` returns `2` where `1` is expected. - `min_value` is only necessary when the table has no rows. It used to be necessary since the 3rd argument of `setval` is always `false`.
Closed since #28864 has been merged to master. |
Is there a fix for this in Rails 4.2? |
Fixes rails#28780 for Rails 4.2
* rails/rails#28780 (comment) * per URL above, monkey-patches AR to fix fixtures:load problem involving sequencing logic changes to Postgres 10 that are incompatible with Rails 4.2
If anyone is on legacy Rails 3.2 here is a version that worked for me and is just slightly modified of what @replaid posted (I just fixed the module/class hierarchy). It landed in my require 'active_record/connection_adapters/postgresql_adapter'
#
# Monkey-patch the refused Rails 4.2 patch at https://github.com/rails/rails/pull/31330
# Changed the module/class hierarchy to work with Rails 3.2
# Based on solution for Rails 4.2 https://github.com/rails/rails/issues/28780#issuecomment-354868174
#
# Updates sequence logic to support PostgreSQL 10.
#
module ActiveRecord
module ConnectionAdapters
class PostgreSQLAdapter
# Resets the sequence of a table's primary key to the maximum value.
def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
unless pk and sequence
default_pk, default_sequence = pk_and_sequence_for(table)
pk ||= default_pk
sequence ||= default_sequence
end
if @logger && pk && !sequence
@logger.warn "#{table} has primary key #{pk} with no default sequence"
end
if pk && sequence
quoted_sequence = quote_table_name(sequence)
max_pk = select_value("SELECT MAX(#{quote_column_name pk}) FROM #{quote_table_name(table)}")
if max_pk.nil?
if postgresql_version >= 100000
minvalue = select_value("SELECT seqmin FROM pg_sequence WHERE seqrelid = #{quote(quoted_sequence)}::regclass")
else
minvalue = select_value("SELECT min_value FROM #{quoted_sequence}")
end
end
select_value <<-end_sql, 'SCHEMA'
SELECT setval(#{quote(quoted_sequence)}, #{max_pk ? max_pk : minvalue}, #{max_pk ? true : false})
end_sql
end
end
end
end
end I was a bit skeptical and wondered if the method that is fixed ( So I think it should work fine |
Copy and paste code from the internet because Ross is lazy. rails/rails#28780
This is a workaround. The bug is fixed in Rails 5.0. Source: rails/rails#28780 (comment)
… not exist in PostgreSQL 10 Reference #1: postgres/postgres@1753b1b Reference #2: rails#28780
… not exist in PostgreSQL 10 Reference #1: postgres/postgres@1753b1b Reference #2: rails#28780
… not exist in PostgreSQL 10 Reference #1: postgres/postgres@1753b1b Reference #2: rails#28780
… not exist in PostgreSQL 10 Reference #1: postgres/postgres@1753b1b Reference #2: rails#28780
… not exist in PostgreSQL 10 Reference #1: postgres/postgres@1753b1b Reference #2: rails#28780
… not exist in PostgreSQL 10 Reference #1: postgres/postgres@1753b1b Reference #2: rails#28780
… not exist in PostgreSQL 10 Reference #1: postgres/postgres@1753b1b Reference #2: rails#28780
… not exist in PostgreSQL 10 Reference #1: postgres/postgres@1753b1b Reference #2: rails#28780
… not exist in PostgreSQL 10 Reference #1: postgres/postgres@1753b1b Reference #2: rails#28780
… not exist in PostgreSQL 10 Reference #1: postgres/postgres@1753b1b Reference #2: rails#28780
…SQL 10. Rails issue: rails/rails#31330 Based on solution for Rails 4.2 rails/rails#28780 (comment)
Rails 4.2 doesn't support PostgreSQL 10 rails/rails#28780
Rails 4.2 doesn't support PostgreSQL 10 rails/rails#28780
* Use ram images * Use PostgreSQL 9 for ruby >= 2.4 Rails 4.2 doesn't support PostgreSQL 10 rails/rails#28780
Environment:
Steps to reproduce:
Results:
Additional information:
It looks this behavior change is introduced by Add pg_sequence system catalog
increment_by
pg_sequences
has itThe text was updated successfully, but these errors were encountered: