Forbid marking an identity column as nullable.
authorTom Lane
Fri, 12 Mar 2021 16:08:42 +0000 (11:08 -0500)
committerTom Lane
Fri, 12 Mar 2021 16:08:42 +0000 (11:08 -0500)
GENERATED ALWAYS AS IDENTITY implies NOT NULL, but the code failed
to complain if you overrode that with "GENERATED ALWAYS AS IDENTITY
NULL".  One might think the old behavior was a feature, but it was
inconsistent because the outcome varied depending on the order of
the clauses, so it seems to have been just an oversight.

Per bug #16913 from Pavel Boev.  Back-patch to v10 where identity
columns were introduced.

Vik Fearing (minor tweaks by me)

Discussion: https://postgr.es/m/16913-3b5198410f67d8c6@postgresql.org

doc/src/sgml/ref/create_table.sgml
src/backend/parser/parse_utilcmd.c
src/test/regress/expected/identity.out
src/test/regress/sql/identity.sql

index 0d257cd170362e14de00696aa242c34ffc63223f..9b349eee3cc4517b86a6f700e447cada6e3e4a3f 100644 (file)
@@ -840,6 +840,7 @@ WITH ( MODULUS numeric_literal, REM
       column.  It will have an implicit sequence attached to it
       and the column in new rows will automatically have values from the
       sequence assigned to it.
+      Such a column is implicitly NOT NULL.
      
 
      
index 577fe1e752e3a38a7c580eeaf83d5ae59b2a8288..a9a98e6b9cf41145aee1ccee049f4ae806729b6a 100644 (file)
@@ -706,7 +706,17 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 
                    column->identity = constraint->generated_when;
                    saw_identity = true;
+
+                   /* An identity column is implicitly NOT NULL */
+                   if (saw_nullable && !column->is_not_null)
+                       ereport(ERROR,
+                               (errcode(ERRCODE_SYNTAX_ERROR),
+                                errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
+                                       column->colname, cxt->relation->relname),
+                                parser_errposition(cxt->pstate,
+                                                   constraint->location)));
                    column->is_not_null = true;
+                   saw_nullable = true;
                    break;
                }
 
index de337d83d75ea996cf38863b40bad8234e9570b7..a36a84bd55e7bfbe9f161fdf3ec133465d2896a0 100644 (file)
@@ -399,3 +399,16 @@ CREATE TABLE itest_child PARTITION OF itest_parent (
 ) FOR VALUES FROM ('2016-07-01') TO ('2016-08-01'); -- error
 ERROR:  identity columns are not supported on partitions
 DROP TABLE itest_parent;
+-- Identity columns must be NOT NULL (cf bug #16913)
+CREATE TABLE itest15 (id integer GENERATED ALWAYS AS IDENTITY NULL); -- fail
+ERROR:  conflicting NULL/NOT NULL declarations for column "id" of table "itest15"
+LINE 1: ...ABLE itest15 (id integer GENERATED ALWAYS AS IDENTITY NULL);
+                                                                 ^
+CREATE TABLE itest15 (id integer NULL GENERATED ALWAYS AS IDENTITY); -- fail
+ERROR:  conflicting NULL/NOT NULL declarations for column "id" of table "itest15"
+LINE 1: CREATE TABLE itest15 (id integer NULL GENERATED ALWAYS AS ID...
+                                              ^
+CREATE TABLE itest15 (id integer GENERATED ALWAYS AS IDENTITY NOT NULL);
+DROP TABLE itest15;
+CREATE TABLE itest15 (id integer NOT NULL GENERATED ALWAYS AS IDENTITY);
+DROP TABLE itest15;
index 40aaf6163d9dd1b0c669f535f92252b4768fe3b3..e93bc7b7e4dbd180ef1ec71fb21a5ab0a8ce471a 100644 (file)
@@ -254,3 +254,12 @@ CREATE TABLE itest_child PARTITION OF itest_parent (
     f3 WITH OPTIONS GENERATED ALWAYS AS IDENTITY
 ) FOR VALUES FROM ('2016-07-01') TO ('2016-08-01'); -- error
 DROP TABLE itest_parent;
+
+-- Identity columns must be NOT NULL (cf bug #16913)
+
+CREATE TABLE itest15 (id integer GENERATED ALWAYS AS IDENTITY NULL); -- fail
+CREATE TABLE itest15 (id integer NULL GENERATED ALWAYS AS IDENTITY); -- fail
+CREATE TABLE itest15 (id integer GENERATED ALWAYS AS IDENTITY NOT NULL);
+DROP TABLE itest15;
+CREATE TABLE itest15 (id integer NOT NULL GENERATED ALWAYS AS IDENTITY);
+DROP TABLE itest15;