Skip to content

Commit 29de882

Browse files
craig[bot]bghal
andcommitted
Merge #154489
154489: sql: fix the starting values of `ALTER`-ed sequences r=bghal a=bghal When altering the minvalue, maxvalue, or increment, a sequence that had either never been advanced with `nextval` or had been exhausted would be set with an incorrect current value. This change better aligns the `ALTER SEQUENCE` behavior to postgres. Fixes: #52552 Informs: #154413, #21564 Release note (sql change): The value of a sequence after an `ALTER SEQUENCE` is now consistent with a sequence created with those values. Co-authored-by: Brendan Gerrity <[email protected]>
2 parents 14ff833 + a58e73f commit 29de882

File tree

2 files changed

+111
-13
lines changed

2 files changed

+111
-13
lines changed

pkg/sql/alter_sequence.go

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func (n *alterSequenceNode) startExec(params runParams) error {
7777
}
7878

7979
// alterSequenceImpl applies given tree.SequenceOptions to the specified sequence descriptor.
80-
// Exisiting sequence options are not overridden with default values.
80+
// Existing sequence options are not overridden with default values.
8181
func alterSequenceImpl(
8282
params runParams,
8383
seqDesc *tabledesc.Mutable,
@@ -86,6 +86,8 @@ func alterSequenceImpl(
8686
) error {
8787
oldMinValue := seqDesc.SequenceOpts.MinValue
8888
oldMaxValue := seqDesc.SequenceOpts.MaxValue
89+
oldIncrement := seqDesc.SequenceOpts.Increment
90+
oldStart := seqDesc.SequenceOpts.Start
8991

9092
existingType := types.Int
9193
if seqDesc.GetSequenceOpts().AsIntegerType != "" {
@@ -120,45 +122,80 @@ func alterSequenceImpl(
120122
if err != nil {
121123
return 0, err
122124
}
125+
123126
return kv.ValueInt(), nil
124127
}
125128

126-
// Due to the semantics of sequence caching (see sql.planner.incrementSequenceUsingCache()),
127-
// it is possible for a sequence to have a value that exceeds its MinValue or MaxValue. Users
128-
// do no see values extending the sequence's bounds, and instead see "bounds exceeded" errors.
129-
// To make a usable again after exceeding its bounds, there are two options:
129+
setSequenceVal := func(val int64) error {
130+
err := params.p.txn.Put(params.ctx, seqValueKey, val)
131+
if err != nil {
132+
return err
133+
}
134+
135+
return nil
136+
}
137+
138+
// Due to the semantics of sequence caching (see sql.planner.incrementSequenceUsingCache()), it
139+
// is possible for a sequence to have a value that exceeds its MinValue or MaxValue. Users do
140+
// not see values beyond the sequence's bounds, and instead see "bounds exceeded" errors. To
141+
// make a sequence usable again after exceeding its bounds, there are two options:
142+
//
130143
// 1. The user changes the sequence's value by calling setval(...)
131-
// 2. The user performs a schema change to alter the sequences MinValue or MaxValue. In this case, the
132-
// value of the sequence must be restored to the original MinValue or MaxValue transactionally.
144+
//
145+
// 2. The user performs a schema change to alter the sequence's MinValue, MaxValue, or
146+
// Increment. In this case, the value of the sequence must be (transactionally) restored to a
147+
// value within MinValue and MaxValue.
148+
//
133149
// The code below handles the second case.
134150

135-
// The sequence is decreasing and the minvalue is being decreased.
136-
if opts.Increment < 0 && seqDesc.SequenceOpts.MinValue < oldMinValue {
151+
if opts.Increment < 0 && (oldIncrement != seqDesc.SequenceOpts.Increment || oldMinValue != seqDesc.SequenceOpts.MinValue) {
152+
// Only get the sequence value from KV if it's needed.
137153
sequenceVal, err := getSequenceValue()
138154
if err != nil {
139155
return err
140156
}
141157

142-
// If the sequence exceeded the old MinValue, it must be changed to start at the old MinValue.
158+
// If the sequence were never advanced, its current value is offset by the increment.
159+
if sequenceVal > oldStart {
160+
err := setSequenceVal(oldStart - seqDesc.SequenceOpts.Increment)
161+
if err != nil {
162+
return err
163+
}
164+
}
165+
166+
// If the sequence were exhausted, it would be beyond its previous bounds.
143167
if sequenceVal < oldMinValue {
144-
err := params.p.txn.Put(params.ctx, seqValueKey, oldMinValue)
168+
// Every call to nextval increments the sequence even if the
169+
// sequence is exhausted. Find the final valid value of the sequence
170+
// by calculating the number of valid calls to it
171+
calls := (oldMinValue - oldStart) / oldIncrement
172+
err := setSequenceVal(oldStart + calls*oldIncrement)
145173
if err != nil {
146174
return err
147175
}
148176
}
149-
} else if opts.Increment > 0 && seqDesc.SequenceOpts.MaxValue > oldMaxValue {
177+
} else if opts.Increment > 0 && (oldIncrement != seqDesc.SequenceOpts.Increment || seqDesc.SequenceOpts.MaxValue > oldMaxValue) {
150178
sequenceVal, err := getSequenceValue()
151179
if err != nil {
152180
return err
153181
}
154182

183+
if sequenceVal < oldStart {
184+
err := setSequenceVal(oldStart - seqDesc.SequenceOpts.Increment)
185+
if err != nil {
186+
return err
187+
}
188+
}
189+
155190
if sequenceVal > oldMaxValue {
156-
err := params.p.txn.Put(params.ctx, seqValueKey, oldMaxValue)
191+
calls := (oldMaxValue - oldStart) / oldIncrement
192+
err := setSequenceVal(oldStart + calls*oldIncrement)
157193
if err != nil {
158194
return err
159195
}
160196
}
161197
}
198+
162199
var restartVal *int64
163200
for _, option := range seqOptions {
164201
if option.Name == tree.SeqOptRestart {

pkg/sql/logictest/testdata/logic_test/alter_sequence

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,3 +395,64 @@ SHOW CREATE SEQUENCE seq_alter_no_min_max_des
395395
----
396396
table_name create_statement
397397
seq_alter_no_min_max_des CREATE SEQUENCE public.seq_alter_no_min_max_des MINVALUE -9223372036854775808 MAXVALUE -1 INCREMENT -1 START -5;
398+
399+
subtest issue-52552
400+
401+
statement ok
402+
CREATE SEQUENCE test_52552_asc INCREMENT BY 3 MINVALUE 1 MAXVALUE 12;
403+
ALTER SEQUENCE test_52552_asc INCREMENT BY 8 MINVALUE 1 MAXVALUE 12;
404+
405+
query II
406+
SELECT nextval('test_52552_asc'), nextval('test_52552_asc');
407+
----
408+
1 9
409+
410+
statement error pq: reached maximum value of sequence "test_52552_asc" \(12\)
411+
SELECT nextval('test_52552_asc');
412+
413+
statement error pq: reached maximum value of sequence "test_52552_asc" \(12\)
414+
SELECT nextval('test_52552_asc');
415+
416+
statement ok
417+
ALTER SEQUENCE test_52552_asc NO MAXVALUE;
418+
419+
query I
420+
SELECT nextval('test_52552_asc');
421+
----
422+
17
423+
424+
statement ok
425+
CREATE SEQUENCE test_52552_desc INCREMENT BY -5 MINVALUE 1 MAXVALUE 12;
426+
ALTER SEQUENCE test_52552_desc INCREMENT BY -8 MINVALUE 1 MAXVALUE 12;
427+
428+
query II
429+
SELECT nextval('test_52552_desc'), nextval('test_52552_desc');
430+
----
431+
12 4
432+
433+
statement error pq: reached minimum value of sequence "test_52552_desc" \(1\)
434+
SELECT nextval('test_52552_desc');
435+
436+
statement error pq: reached minimum value of sequence "test_52552_desc" \(1\)
437+
SELECT nextval('test_52552_desc');
438+
439+
statement ok
440+
ALTER SEQUENCE test_52552_desc NO MINVALUE;
441+
442+
query I
443+
SELECT nextval('test_52552_desc');
444+
----
445+
-4
446+
447+
statement ok
448+
CREATE SEQUENCE test_52552_start INCREMENT BY 3 MINVALUE 1 MAXVALUE 100 START 50;
449+
450+
statement ok
451+
ALTER SEQUENCE test_52552_start INCREMENT BY 8;
452+
453+
query I
454+
SELECT nextval('test_52552_start');
455+
----
456+
50
457+
458+
subtest end

0 commit comments

Comments
 (0)