Skip to content

Commit 60a0b2e

Browse files
committed
Adjust min/max values when changing sequence type
When changing the type of a sequence, adjust the min/max values of the sequence if it looks like the previous values were the default values. Previously, it would leave the old values in place, requiring manual adjustments even in the usual/default cases. Reviewed-by: Michael Paquier <michael.paquier@gmail.com> Reviewed-by: Vitaly Burovoy <vitaly.burovoy@gmail.com>
1 parent a9a7949 commit 60a0b2e

File tree

4 files changed

+96
-22
lines changed

4 files changed

+96
-22
lines changed

doc/src/sgml/ref/alter_sequence.sgml

+9-4
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,15 @@ ALTER SEQUENCE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> S
9494
</para>
9595

9696
<para>
97-
Note that changing the data type does not automatically change the
98-
minimum and maximum values. You can use the clauses <literal>NO
99-
MINVALUE</literal> and <literal>NO MAXVALUE</literal> to adjust the
100-
minimum and maximum values to the range of the new data type.
97+
Changing the data type automatically changes the minimum and maximum
98+
values of the sequence if and only if the previous minimum and maximum
99+
values were the minimum or maximum value of the old data type (in
100+
other words, if the sequence had been created using <literal>NO
101+
MINVALUE</literal> or <literal>NO MAXVALUE</literal>, implicitly or
102+
explicitly). Otherwise, the minimum and maximum values are preserved,
103+
unless new values are given as part of the same command. If the
104+
minimum and maximum values do not fit into the new data type, an error
105+
will be generated.
101106
</para>
102107
</listitem>
103108
</varlistentry>

src/backend/commands/sequence.c

+33-10
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,8 @@ init_params(ParseState *pstate, List *options, bool isInit,
12321232
DefElem *cache_value = NULL;
12331233
DefElem *is_cycled = NULL;
12341234
ListCell *option;
1235+
bool reset_max_value = false;
1236+
bool reset_min_value = false;
12351237

12361238
*owned_by = NIL;
12371239

@@ -1335,13 +1337,34 @@ init_params(ParseState *pstate, List *options, bool isInit,
13351337
/* AS type */
13361338
if (as_type != NULL)
13371339
{
1338-
seqform->seqtypid = typenameTypeId(pstate, defGetTypeName(as_type));
1339-
if (seqform->seqtypid != INT2OID &&
1340-
seqform->seqtypid != INT4OID &&
1341-
seqform->seqtypid != INT8OID)
1340+
Oid newtypid = typenameTypeId(pstate, defGetTypeName(as_type));
1341+
1342+
if (newtypid != INT2OID &&
1343+
newtypid != INT4OID &&
1344+
newtypid != INT8OID)
13421345
ereport(ERROR,
13431346
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
13441347
errmsg("sequence type must be smallint, integer, or bigint")));
1348+
1349+
if (!isInit)
1350+
{
1351+
/*
1352+
* When changing type and the old sequence min/max values were the
1353+
* min/max of the old type, adjust sequence min/max values to
1354+
* min/max of new type. (Otherwise, the user chose explicit
1355+
* min/max values, which we'll leave alone.)
1356+
*/
1357+
if ((seqform->seqtypid == INT2OID && seqform->seqmax == PG_INT16_MAX) ||
1358+
(seqform->seqtypid == INT4OID && seqform->seqmax == PG_INT32_MAX) ||
1359+
(seqform->seqtypid == INT8OID && seqform->seqmax == PG_INT64_MAX))
1360+
reset_max_value = true;
1361+
if ((seqform->seqtypid == INT2OID && seqform->seqmin == PG_INT16_MIN) ||
1362+
(seqform->seqtypid == INT4OID && seqform->seqmin == PG_INT32_MIN) ||
1363+
(seqform->seqtypid == INT8OID && seqform->seqmin == PG_INT64_MIN))
1364+
reset_min_value = true;
1365+
}
1366+
1367+
seqform->seqtypid = newtypid;
13451368
}
13461369
else if (isInit)
13471370
seqform->seqtypid = INT8OID;
@@ -1375,9 +1398,9 @@ init_params(ParseState *pstate, List *options, bool isInit,
13751398
seqform->seqmax = defGetInt64(max_value);
13761399
seqdataform->log_cnt = 0;
13771400
}
1378-
else if (isInit || max_value != NULL)
1401+
else if (isInit || max_value != NULL || reset_max_value)
13791402
{
1380-
if (seqform->seqincrement > 0)
1403+
if (seqform->seqincrement > 0 || reset_max_value)
13811404
{
13821405
/* ascending seq */
13831406
if (seqform->seqtypid == INT2OID)
@@ -1412,11 +1435,9 @@ init_params(ParseState *pstate, List *options, bool isInit,
14121435
seqform->seqmin = defGetInt64(min_value);
14131436
seqdataform->log_cnt = 0;
14141437
}
1415-
else if (isInit || min_value != NULL)
1438+
else if (isInit || min_value != NULL || reset_min_value)
14161439
{
1417-
if (seqform->seqincrement > 0)
1418-
seqform->seqmin = 1; /* ascending seq */
1419-
else
1440+
if (seqform->seqincrement < 0 || reset_min_value)
14201441
{
14211442
/* descending seq */
14221443
if (seqform->seqtypid == INT2OID)
@@ -1426,6 +1447,8 @@ init_params(ParseState *pstate, List *options, bool isInit,
14261447
else
14271448
seqform->seqmin = PG_INT64_MIN;
14281449
}
1450+
else
1451+
seqform->seqmin = 1; /* ascending seq */
14291452
seqdataform->log_cnt = 0;
14301453
}
14311454

src/test/regress/expected/sequence.out

+35-5
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,35 @@ DROP TABLE sequence_test_table;
3232
CREATE SEQUENCE sequence_test5 AS integer;
3333
CREATE SEQUENCE sequence_test6 AS smallint;
3434
CREATE SEQUENCE sequence_test7 AS bigint;
35+
CREATE SEQUENCE sequence_test8 AS integer MAXVALUE 100000;
36+
CREATE SEQUENCE sequence_test9 AS integer INCREMENT BY -1;
37+
CREATE SEQUENCE sequence_test10 AS integer MINVALUE -100000 START 1;
38+
CREATE SEQUENCE sequence_test11 AS smallint;
39+
CREATE SEQUENCE sequence_test12 AS smallint INCREMENT -1;
40+
CREATE SEQUENCE sequence_test13 AS smallint MINVALUE -32768;
41+
CREATE SEQUENCE sequence_test14 AS smallint MAXVALUE 32767 INCREMENT -1;
3542
CREATE SEQUENCE sequence_testx AS text;
3643
ERROR: sequence type must be smallint, integer, or bigint
3744
CREATE SEQUENCE sequence_testx AS nosuchtype;
3845
ERROR: type "nosuchtype" does not exist
3946
LINE 1: CREATE SEQUENCE sequence_testx AS nosuchtype;
4047
^
41-
ALTER SEQUENCE sequence_test5 AS smallint; -- fails
42-
ERROR: MAXVALUE (2147483647) is out of range for sequence data type smallint
43-
ALTER SEQUENCE sequence_test5 AS smallint NO MINVALUE NO MAXVALUE;
4448
CREATE SEQUENCE sequence_testx AS smallint MAXVALUE 100000;
4549
ERROR: MAXVALUE (100000) is out of range for sequence data type smallint
4650
CREATE SEQUENCE sequence_testx AS smallint MINVALUE -100000;
4751
ERROR: MINVALUE (-100000) is out of range for sequence data type smallint
52+
ALTER SEQUENCE sequence_test5 AS smallint; -- success, max will be adjusted
53+
ALTER SEQUENCE sequence_test8 AS smallint; -- fail, max has to be adjusted
54+
ERROR: MAXVALUE (100000) is out of range for sequence data type smallint
55+
ALTER SEQUENCE sequence_test8 AS smallint MAXVALUE 20000; -- ok now
56+
ALTER SEQUENCE sequence_test9 AS smallint; -- success, min will be adjusted
57+
ALTER SEQUENCE sequence_test10 AS smallint; -- fail, min has to be adjusted
58+
ERROR: MINVALUE (-100000) is out of range for sequence data type smallint
59+
ALTER SEQUENCE sequence_test10 AS smallint MINVALUE -20000; -- ok now
60+
ALTER SEQUENCE sequence_test11 AS int; -- max will be adjusted
61+
ALTER SEQUENCE sequence_test12 AS int; -- min will be adjusted
62+
ALTER SEQUENCE sequence_test13 AS int; -- min and max will be adjusted
63+
ALTER SEQUENCE sequence_test14 AS int; -- min and max will be adjusted
4864
---
4965
--- test creation of SERIAL column
5066
---
@@ -459,39 +475,53 @@ SELECT * FROM information_schema.sequences
459475
ORDER BY sequence_name ASC;
460476
sequence_catalog | sequence_schema | sequence_name | data_type | numeric_precision | numeric_precision_radix | numeric_scale | start_value | minimum_value | maximum_value | increment | cycle_option
461477
------------------+-----------------+--------------------+-----------+-------------------+-------------------------+---------------+-------------+----------------------+---------------------+-----------+--------------
478+
regression | public | sequence_test10 | smallint | 16 | 2 | 0 | 1 | -20000 | 32767 | 1 | NO
479+
regression | public | sequence_test11 | integer | 32 | 2 | 0 | 1 | 1 | 2147483647 | 1 | NO
480+
regression | public | sequence_test12 | integer | 32 | 2 | 0 | -1 | -2147483648 | -1 | -1 | NO
481+
regression | public | sequence_test13 | integer | 32 | 2 | 0 | -32768 | -2147483648 | 2147483647 | 1 | NO
482+
regression | public | sequence_test14 | integer | 32 | 2 | 0 | 32767 | -2147483648 | 2147483647 | -1 | NO
462483
regression | public | sequence_test2 | bigint | 64 | 2 | 0 | 32 | 5 | 36 | 4 | YES
463484
regression | public | sequence_test3 | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO
464485
regression | public | sequence_test4 | bigint | 64 | 2 | 0 | -1 | -9223372036854775808 | -1 | -1 | NO
465486
regression | public | sequence_test5 | smallint | 16 | 2 | 0 | 1 | 1 | 32767 | 1 | NO
466487
regression | public | sequence_test6 | smallint | 16 | 2 | 0 | 1 | 1 | 32767 | 1 | NO
467488
regression | public | sequence_test7 | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO
489+
regression | public | sequence_test8 | smallint | 16 | 2 | 0 | 1 | 1 | 20000 | 1 | NO
490+
regression | public | sequence_test9 | smallint | 16 | 2 | 0 | -1 | -32768 | -1 | -1 | NO
468491
regression | public | serialtest1_f2_foo | integer | 32 | 2 | 0 | 1 | 1 | 2147483647 | 1 | NO
469492
regression | public | serialtest2_f2_seq | integer | 32 | 2 | 0 | 1 | 1 | 2147483647 | 1 | NO
470493
regression | public | serialtest2_f3_seq | smallint | 16 | 2 | 0 | 1 | 1 | 32767 | 1 | NO
471494
regression | public | serialtest2_f4_seq | smallint | 16 | 2 | 0 | 1 | 1 | 32767 | 1 | NO
472495
regression | public | serialtest2_f5_seq | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO
473496
regression | public | serialtest2_f6_seq | bigint | 64 | 2 | 0 | 1 | 1 | 9223372036854775807 | 1 | NO
474-
(12 rows)
497+
(19 rows)
475498

476499
SELECT schemaname, sequencename, start_value, min_value, max_value, increment_by, cycle, cache_size, last_value
477500
FROM pg_sequences
478501
WHERE sequencename ~ ANY(ARRAY['sequence_test', 'serialtest'])
479502
ORDER BY sequencename ASC;
480503
schemaname | sequencename | start_value | min_value | max_value | increment_by | cycle | cache_size | last_value
481504
------------+--------------------+-------------+----------------------+---------------------+--------------+-------+------------+------------
505+
public | sequence_test10 | 1 | -20000 | 32767 | 1 | f | 1 |
506+
public | sequence_test11 | 1 | 1 | 2147483647 | 1 | f | 1 |
507+
public | sequence_test12 | -1 | -2147483648 | -1 | -1 | f | 1 |
508+
public | sequence_test13 | -32768 | -2147483648 | 2147483647 | 1 | f | 1 |
509+
public | sequence_test14 | 32767 | -2147483648 | 2147483647 | -1 | f | 1 |
482510
public | sequence_test2 | 32 | 5 | 36 | 4 | t | 1 | 5
483511
public | sequence_test3 | 1 | 1 | 9223372036854775807 | 1 | f | 1 |
484512
public | sequence_test4 | -1 | -9223372036854775808 | -1 | -1 | f | 1 | -1
485513
public | sequence_test5 | 1 | 1 | 32767 | 1 | f | 1 |
486514
public | sequence_test6 | 1 | 1 | 32767 | 1 | f | 1 |
487515
public | sequence_test7 | 1 | 1 | 9223372036854775807 | 1 | f | 1 |
516+
public | sequence_test8 | 1 | 1 | 20000 | 1 | f | 1 |
517+
public | sequence_test9 | -1 | -32768 | -1 | -1 | f | 1 |
488518
public | serialtest1_f2_foo | 1 | 1 | 2147483647 | 1 | f | 1 | 3
489519
public | serialtest2_f2_seq | 1 | 1 | 2147483647 | 1 | f | 1 | 2
490520
public | serialtest2_f3_seq | 1 | 1 | 32767 | 1 | f | 1 | 2
491521
public | serialtest2_f4_seq | 1 | 1 | 32767 | 1 | f | 1 | 2
492522
public | serialtest2_f5_seq | 1 | 1 | 9223372036854775807 | 1 | f | 1 | 2
493523
public | serialtest2_f6_seq | 1 | 1 | 9223372036854775807 | 1 | f | 1 | 2
494-
(12 rows)
524+
(19 rows)
495525

496526
SELECT * FROM pg_sequence_parameters('sequence_test4'::regclass);
497527
start_value | minimum_value | maximum_value | increment | cycle_option | cache_size | data_type

src/test/regress/sql/sequence.sql

+19-3
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,31 @@ DROP TABLE sequence_test_table;
2323
CREATE SEQUENCE sequence_test5 AS integer;
2424
CREATE SEQUENCE sequence_test6 AS smallint;
2525
CREATE SEQUENCE sequence_test7 AS bigint;
26+
CREATE SEQUENCE sequence_test8 AS integer MAXVALUE 100000;
27+
CREATE SEQUENCE sequence_test9 AS integer INCREMENT BY -1;
28+
CREATE SEQUENCE sequence_test10 AS integer MINVALUE -100000 START 1;
29+
CREATE SEQUENCE sequence_test11 AS smallint;
30+
CREATE SEQUENCE sequence_test12 AS smallint INCREMENT -1;
31+
CREATE SEQUENCE sequence_test13 AS smallint MINVALUE -32768;
32+
CREATE SEQUENCE sequence_test14 AS smallint MAXVALUE 32767 INCREMENT -1;
2633
CREATE SEQUENCE sequence_testx AS text;
2734
CREATE SEQUENCE sequence_testx AS nosuchtype;
2835

29-
ALTER SEQUENCE sequence_test5 AS smallint; -- fails
30-
ALTER SEQUENCE sequence_test5 AS smallint NO MINVALUE NO MAXVALUE;
31-
3236
CREATE SEQUENCE sequence_testx AS smallint MAXVALUE 100000;
3337
CREATE SEQUENCE sequence_testx AS smallint MINVALUE -100000;
3438

39+
ALTER SEQUENCE sequence_test5 AS smallint; -- success, max will be adjusted
40+
ALTER SEQUENCE sequence_test8 AS smallint; -- fail, max has to be adjusted
41+
ALTER SEQUENCE sequence_test8 AS smallint MAXVALUE 20000; -- ok now
42+
ALTER SEQUENCE sequence_test9 AS smallint; -- success, min will be adjusted
43+
ALTER SEQUENCE sequence_test10 AS smallint; -- fail, min has to be adjusted
44+
ALTER SEQUENCE sequence_test10 AS smallint MINVALUE -20000; -- ok now
45+
46+
ALTER SEQUENCE sequence_test11 AS int; -- max will be adjusted
47+
ALTER SEQUENCE sequence_test12 AS int; -- min will be adjusted
48+
ALTER SEQUENCE sequence_test13 AS int; -- min and max will be adjusted
49+
ALTER SEQUENCE sequence_test14 AS int; -- min and max will be adjusted
50+
3551
---
3652
--- test creation of SERIAL column
3753
---

0 commit comments

Comments
 (0)