diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index ad28225b36..25c605bfc5 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -404,7 +404,9 @@ fill_seq_with_data(Relation rel, HeapTuple tuple) /* * AlterSequence * - * Modify the definition of a sequence relation + * Modify the definition of a sequence relation. The operation is not + * transactional and uses a minimal locking to not disrupt parallel + * sessions working with this sequence. */ ObjectAddress AlterSequence(ParseState *pstate, AlterSeqStmt *stmt) @@ -439,7 +441,11 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, stmt->sequence->relname); - /* lock page' buffer and read tuple into new sequence structure */ + /* + * Lock page buffer and read tuple into new sequence structure. + * The lock is hold for the duration of the tuple update in the + * catalog. + */ seqdata = read_seq_tuple(seqrel, &buf, &seqdatatuple); /* Copy old values of options into workspace */ @@ -494,8 +500,6 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt) END_CRIT_SECTION(); - UnlockReleaseBuffer(buf); - /* process OWNED BY if given */ if (owned_by) process_owned_by(seqrel, owned_by, stmt->for_identity); @@ -506,9 +510,12 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt) relation_close(seqrel, NoLock); - CatalogTupleUpdate(rel, &tuple->t_self, tuple); + heap_inplace_update(rel, tuple); + heap_close(rel, RowExclusiveLock); + UnlockReleaseBuffer(buf); + return address; } diff --git a/src/test/isolation/expected/alter-sequence.out b/src/test/isolation/expected/alter-sequence.out new file mode 100644 index 0000000000..d0937f0f48 --- /dev/null +++ b/src/test/isolation/expected/alter-sequence.out @@ -0,0 +1,14 @@ +Parsed test spec with 2 sessions + +starting permutation: b1 as1 as2 c1 +step b1: BEGIN; +step as1: ALTER SEQUENCE myseq MAXVALUE 10; +step as2: ALTER SEQUENCE myseq RESTART 1; +step c1: COMMIT; + +starting permutation: b1 as1 q2 c1 +step b1: BEGIN; +step as1: ALTER SEQUENCE myseq MAXVALUE 10; +step q2: SELECT nextval('myseq') FROM generate_series(1, 12); +ERROR: nextval: reached maximum value of sequence "myseq" (10) +step c1: COMMIT; diff --git a/src/test/isolation/specs/alter-sequence.spec b/src/test/isolation/specs/alter-sequence.spec new file mode 100644 index 0000000000..b9a4ce601f --- /dev/null +++ b/src/test/isolation/specs/alter-sequence.spec @@ -0,0 +1,25 @@ +# ALTER SEQUENCE - Set and use of values + +setup +{ + CREATE SEQUENCE myseq; +} + +teardown +{ + DROP SEQUENCE myseq; +} + +session "s1" +step "b1" { BEGIN; } +step "as1" { ALTER SEQUENCE myseq MAXVALUE 10; } +step "c1" { COMMIT; } + +session "s2" +step "as2" { ALTER SEQUENCE myseq RESTART 1; } +step "q2" { SELECT nextval('myseq') FROM generate_series(1, 12); } + +# No concurrency errors +permutation "b1" "as1" "as2" "c1" +# nextval() call will fail because of MAXVALUE changed +permutation "b1" "as1" "q2" "c1"