From 03db510539b4f0ebc4fea35dd07bcb7630198e5c Mon Sep 17 00:00:00 2001
From: Vitaly Burovoy <vitaly.burovoy@gmail.com>
Date: Fri, 31 Mar 2017 02:25:23 +0000
Subject: [PATCH 2/2] Fix overriding max/min value of a sequence to +-1 on
 "ALTER...AS type"

If the max/min value match the bounds of the old type and neither
MAXVALUE/MINVALUE nor NO MAXVALUE/NO MINVALUE are set, change values to the
bounds of the new type, not treat it as NO MAXVALUE/NO MINVALUE.
---
 src/backend/commands/sequence.c        |  4 ++--
 src/test/regress/expected/sequence.out | 41 ++++++++++++++++++++++++++++++++--
 src/test/regress/sql/sequence.sql      | 21 +++++++++++++++++
 3 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 3f0e9d5..c2ee7d6 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1400,7 +1400,7 @@ init_params(ParseState *pstate, List *options, bool isInit,
 	}
 	else if (isInit || max_value != NULL || reset_max_value)
 	{
-		if (seqform->seqincrement > 0)
+		if (seqform->seqincrement > 0 || reset_max_value)
 		{
 			/* ascending seq */
 			if (seqform->seqtypid == INT2OID)
@@ -1437,7 +1437,7 @@ init_params(ParseState *pstate, List *options, bool isInit,
 	}
 	else if (isInit || min_value != NULL || reset_min_value)
 	{
-		if (seqform->seqincrement > 0)
+		if (seqform->seqincrement > 0 && !reset_min_value)
 			seqform->seqmin = 1; /* ascending seq */
 		else
 		{
diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out
index a5de1f3..7464d7c 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -33,6 +33,11 @@ CREATE SEQUENCE sequence_test5 AS integer;
 CREATE SEQUENCE sequence_test6 AS smallint;
 CREATE SEQUENCE sequence_test7 AS bigint;
 CREATE SEQUENCE sequence_test8 AS integer MAXVALUE 100000;
+CREATE SEQUENCE sequence_test9 AS integer MINVALUE -100000 START 1;
+CREATE SEQUENCE sequence_testa AS smallint;
+CREATE SEQUENCE sequence_testb AS smallint INCREMENT -1;
+CREATE SEQUENCE sequence_testc AS smallint MINVALUE -32768;
+CREATE SEQUENCE sequence_testd AS smallint MAXVALUE 32767 INCREMENT -1;
 CREATE SEQUENCE sequence_testx AS text;
 ERROR:  sequence type must be smallint, integer, or bigint
 CREATE SEQUENCE sequence_testx AS nosuchtype;
@@ -47,6 +52,28 @@ ALTER SEQUENCE sequence_test5 AS smallint;  -- success, max will be adjusted
 ALTER SEQUENCE sequence_test8 AS smallint;  -- fail, max has to be adjusted
 ERROR:  MAXVALUE (100000) is out of range for sequence data type smallint
 ALTER SEQUENCE sequence_test8 AS smallint MAXVALUE 20000;  -- ok now
+ALTER SEQUENCE sequence_test9 AS smallint;  -- fail, min has to be adjusted
+ERROR:  MINVALUE (-100000) is out of range for sequence data type smallint
+ALTER SEQUENCE sequence_test9 AS smallint MINVALUE -20000;  -- ok now
+ALTER SEQUENCE sequence_testa AS int;  -- enlarge a single bound
+ALTER SEQUENCE sequence_testb AS int;  -- enlarge a single bound
+ALTER SEQUENCE sequence_testc AS int;  -- enlarge both bounds
+ALTER SEQUENCE sequence_testd AS int;  -- enlarge both bounds
+SELECT schemaname, sequencename, start_value, min_value, max_value, increment_by, cycle, cache_size, last_value
+FROM pg_sequences
+WHERE sequencename IN('sequence_testa', 'sequence_testb', 'sequence_testc', 'sequence_testd')
+  ORDER BY sequencename ASC;
+ schemaname |  sequencename  | start_value |  min_value  | max_value  | increment_by | cycle | cache_size | last_value 
+------------+----------------+-------------+-------------+------------+--------------+-------+------------+------------
+ public     | sequence_testa |           1 |           1 | 2147483647 |            1 | f     |          1 |           
+ public     | sequence_testb |          -1 | -2147483648 |         -1 |           -1 | f     |          1 |           
+ public     | sequence_testc |      -32768 | -2147483648 | 2147483647 |            1 | f     |          1 |           
+ public     | sequence_testd |       32767 | -2147483648 | 2147483647 |           -1 | f     |          1 |           
+(4 rows)
+
+ALTER SEQUENCE sequence_testa AS int;  -- shrink a single bound
+ALTER SEQUENCE sequence_testb AS int;  -- shrink both bounds
+ALTER SEQUENCE sequence_testc AS int;  -- shrink both bounds
 ---
 --- test creation of SERIAL column
 ---
@@ -468,13 +495,18 @@ SELECT * FROM information_schema.sequences
  regression       | public          | sequence_test6     | smallint  |                16 |                       2 |             0 | 1           | 1                    | 32767               | 1         | NO
  regression       | public          | sequence_test7     | bigint    |                64 |                       2 |             0 | 1           | 1                    | 9223372036854775807 | 1         | NO
  regression       | public          | sequence_test8     | smallint  |                16 |                       2 |             0 | 1           | 1                    | 20000               | 1         | NO
+ regression       | public          | sequence_test9     | smallint  |                16 |                       2 |             0 | 1           | -20000               | 32767               | 1         | NO
+ regression       | public          | sequence_testa     | integer   |                32 |                       2 |             0 | 1           | 1                    | 2147483647          | 1         | NO
+ regression       | public          | sequence_testb     | integer   |                32 |                       2 |             0 | -1          | -2147483648          | -1                  | -1        | NO
+ regression       | public          | sequence_testc     | integer   |                32 |                       2 |             0 | -32768      | -2147483648          | 2147483647          | 1         | NO
+ regression       | public          | sequence_testd     | integer   |                32 |                       2 |             0 | 32767       | -2147483648          | 2147483647          | -1        | NO
  regression       | public          | serialtest1_f2_foo | integer   |                32 |                       2 |             0 | 1           | 1                    | 2147483647          | 1         | NO
  regression       | public          | serialtest2_f2_seq | integer   |                32 |                       2 |             0 | 1           | 1                    | 2147483647          | 1         | NO
  regression       | public          | serialtest2_f3_seq | smallint  |                16 |                       2 |             0 | 1           | 1                    | 32767               | 1         | NO
  regression       | public          | serialtest2_f4_seq | smallint  |                16 |                       2 |             0 | 1           | 1                    | 32767               | 1         | NO
  regression       | public          | serialtest2_f5_seq | bigint    |                64 |                       2 |             0 | 1           | 1                    | 9223372036854775807 | 1         | NO
  regression       | public          | serialtest2_f6_seq | bigint    |                64 |                       2 |             0 | 1           | 1                    | 9223372036854775807 | 1         | NO
-(13 rows)
+(18 rows)
 
 SELECT schemaname, sequencename, start_value, min_value, max_value, increment_by, cycle, cache_size, last_value
 FROM pg_sequences
@@ -489,13 +521,18 @@ WHERE sequencename ~ ANY(ARRAY['sequence_test', 'serialtest'])
  public     | sequence_test6     |           1 |                    1 |               32767 |            1 | f     |          1 |           
  public     | sequence_test7     |           1 |                    1 | 9223372036854775807 |            1 | f     |          1 |           
  public     | sequence_test8     |           1 |                    1 |               20000 |            1 | f     |          1 |           
+ public     | sequence_test9     |           1 |               -20000 |               32767 |            1 | f     |          1 |           
+ public     | sequence_testa     |           1 |                    1 |          2147483647 |            1 | f     |          1 |           
+ public     | sequence_testb     |          -1 |          -2147483648 |                  -1 |           -1 | f     |          1 |           
+ public     | sequence_testc     |      -32768 |          -2147483648 |          2147483647 |            1 | f     |          1 |           
+ public     | sequence_testd     |       32767 |          -2147483648 |          2147483647 |           -1 | f     |          1 |           
  public     | serialtest1_f2_foo |           1 |                    1 |          2147483647 |            1 | f     |          1 |          3
  public     | serialtest2_f2_seq |           1 |                    1 |          2147483647 |            1 | f     |          1 |          2
  public     | serialtest2_f3_seq |           1 |                    1 |               32767 |            1 | f     |          1 |          2
  public     | serialtest2_f4_seq |           1 |                    1 |               32767 |            1 | f     |          1 |          2
  public     | serialtest2_f5_seq |           1 |                    1 | 9223372036854775807 |            1 | f     |          1 |          2
  public     | serialtest2_f6_seq |           1 |                    1 | 9223372036854775807 |            1 | f     |          1 |          2
-(13 rows)
+(18 rows)
 
 SELECT * FROM pg_sequence_parameters('sequence_test4'::regclass);
  start_value |    minimum_value     | maximum_value | increment | cycle_option | cache_size | data_type 
diff --git a/src/test/regress/sql/sequence.sql b/src/test/regress/sql/sequence.sql
index 8f8d54b..1d04f65 100644
--- a/src/test/regress/sql/sequence.sql
+++ b/src/test/regress/sql/sequence.sql
@@ -24,6 +24,11 @@ CREATE SEQUENCE sequence_test5 AS integer;
 CREATE SEQUENCE sequence_test6 AS smallint;
 CREATE SEQUENCE sequence_test7 AS bigint;
 CREATE SEQUENCE sequence_test8 AS integer MAXVALUE 100000;
+CREATE SEQUENCE sequence_test9 AS integer MINVALUE -100000 START 1;
+CREATE SEQUENCE sequence_testa AS smallint;
+CREATE SEQUENCE sequence_testb AS smallint INCREMENT -1;
+CREATE SEQUENCE sequence_testc AS smallint MINVALUE -32768;
+CREATE SEQUENCE sequence_testd AS smallint MAXVALUE 32767 INCREMENT -1;
 CREATE SEQUENCE sequence_testx AS text;
 CREATE SEQUENCE sequence_testx AS nosuchtype;
 
@@ -33,6 +38,22 @@ CREATE SEQUENCE sequence_testx AS smallint MINVALUE -100000;
 ALTER SEQUENCE sequence_test5 AS smallint;  -- success, max will be adjusted
 ALTER SEQUENCE sequence_test8 AS smallint;  -- fail, max has to be adjusted
 ALTER SEQUENCE sequence_test8 AS smallint MAXVALUE 20000;  -- ok now
+ALTER SEQUENCE sequence_test9 AS smallint;  -- fail, min has to be adjusted
+ALTER SEQUENCE sequence_test9 AS smallint MINVALUE -20000;  -- ok now
+
+ALTER SEQUENCE sequence_testa AS int;  -- enlarge a single bound
+ALTER SEQUENCE sequence_testb AS int;  -- enlarge a single bound
+ALTER SEQUENCE sequence_testc AS int;  -- enlarge both bounds
+ALTER SEQUENCE sequence_testd AS int;  -- enlarge both bounds
+
+SELECT schemaname, sequencename, start_value, min_value, max_value, increment_by, cycle, cache_size, last_value
+FROM pg_sequences
+WHERE sequencename IN('sequence_testa', 'sequence_testb', 'sequence_testc', 'sequence_testd')
+  ORDER BY sequencename ASC;
+
+ALTER SEQUENCE sequence_testa AS int;  -- shrink a single bound
+ALTER SEQUENCE sequence_testb AS int;  -- shrink both bounds
+ALTER SEQUENCE sequence_testc AS int;  -- shrink both bounds
 
 ---
 --- test creation of SERIAL column
-- 
2.7.3

