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 ca0855d71316e50819f792f04327d102cd315fc8..e56c4af9b1747d2ec24214628e260391fbeaf1be 100644 (file)
@@ -839,6 +839,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 c4076a3868ba77ea6d3b308eb41efeccbc6e6a28..49a898b64617810583baa9759ee98ba019717ecf 100644 (file)
@@ -716,7 +716,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 2238f896f9a483040c373539c71b47b5196d1d4a..069a42b70cfd5eee4acc0f32759e87468a46aaa8 100644 (file)
@@ -491,3 +491,16 @@ CREATE TABLE itest14 (id serial);
 ALTER TABLE itest14 ALTER id DROP DEFAULT;
 ALTER TABLE itest14 ALTER id ADD GENERATED BY DEFAULT AS IDENTITY;
 INSERT INTO itest14 (id) VALUES (DEFAULT);
+-- 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 d4bc29ab5c30072efbfcb7d8a5f0b7a820d5c55a..6e5cb1b9e0959c45f643ceed9f98487f4dcabdea 100644 (file)
@@ -323,3 +323,12 @@ CREATE TABLE itest14 (id serial);
 ALTER TABLE itest14 ALTER id DROP DEFAULT;
 ALTER TABLE itest14 ALTER id ADD GENERATED BY DEFAULT AS IDENTITY;
 INSERT INTO itest14 (id) VALUES (DEFAULT);
+
+-- 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;