Extended SERIAL parsing - Mailing list pgsql-hackers

From Zoltan Boszormenyi
Subject Extended SERIAL parsing
Date
Msg-id 448C9B7A.6010000@dunaweb.hu
Whole thread Raw
Responses Re: Extended SERIAL parsing  (Rod Taylor <pg@rbt.ca>)
Re: Extended SERIAL parsing  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-hackers
Hi,

after some experimentation, I came up with the attached patch,
which implements parsing the following SERIAL types:

SERIAL
SERIAL GENERATED { ALWAYS | BY DEFAULT }
SERIAL GENERATED [ ALWAYS | BY DEFAULT ] AS IDENTITY( sequence options )

The underlying type is still int4 or int8,
so the problems you discussed aren't solved.
But at least the current semantics is kept.

It passes all regression tests, and it works, too:

# create table proba (i serial generated as identity(minvalue 5 maxvalue
10) primary key, t text);
NOTICE:  CREATE TABLE will create implicit sequence "proba_i_seq" for
serial column "proba.i"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index
"proba_pkey" for table "proba"
CREATE TABLE
# insert into proba (t) values ('a');
INSERT 0 1
# select * from proba;
 i | t
---+---
 5 | a
(1 row)

For now, GENERATED { ALWAYS | BY DEFAULT }
are just fillings.

The condition (column->is_serial && column->force_default)
can help enforcing GENERATED ALWAYS at INSERT time
and can also help fixing the two TODO entries about SERIAL.

Best regards,
Zoltán Böszörményi

diff -ur postgresql-8.2/src/backend/parser/analyze.c postgresql-8.2-serial/src/backend/parser/analyze.c
--- postgresql-8.2/src/backend/parser/analyze.c    2006-04-30 20:30:39.000000000 +0200
+++ postgresql-8.2-serial/src/backend/parser/analyze.c    2006-06-11 23:36:22.000000000 +0200
@@ -825,40 +825,17 @@
 transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                           ColumnDef *column)
 {
-    bool        is_serial;
     bool        saw_nullable;
     Constraint *constraint;
     ListCell   *clist;

     cxt->columns = lappend(cxt->columns, column);

-    /* Check for SERIAL pseudo-types */
-    is_serial = false;
-    if (list_length(column->typename->names) == 1)
-    {
-        char       *typname = strVal(linitial(column->typename->names));
-
-        if (strcmp(typname, "serial") == 0 ||
-            strcmp(typname, "serial4") == 0)
-        {
-            is_serial = true;
-            column->typename->names = NIL;
-            column->typename->typeid = INT4OID;
-        }
-        else if (strcmp(typname, "bigserial") == 0 ||
-                 strcmp(typname, "serial8") == 0)
-        {
-            is_serial = true;
-            column->typename->names = NIL;
-            column->typename->typeid = INT8OID;
-        }
-    }
-
     /* Do necessary work on the column type declaration */
     transformColumnType(pstate, column);

     /* Special actions for SERIAL pseudo-types */
-    if (is_serial)
+    if (column->is_serial)
     {
         Oid            snamespaceid;
         char       *snamespace;
@@ -898,7 +875,7 @@
          */
         seqstmt = makeNode(CreateSeqStmt);
         seqstmt->sequence = makeRangeVar(snamespace, sname);
-        seqstmt->options = NIL;
+        seqstmt->options = column->seq_opts;

         cxt->blist = lappend(cxt->blist, seqstmt);

diff -ur postgresql-8.2/src/backend/parser/gram.y postgresql-8.2-serial/src/backend/parser/gram.y
--- postgresql-8.2/src/backend/parser/gram.y    2006-05-27 19:38:45.000000000 +0200
+++ postgresql-8.2-serial/src/backend/parser/gram.y    2006-06-11 23:42:02.000000000 +0200
@@ -275,6 +275,7 @@
 %type <boolean> opt_instead opt_analyze
 %type <boolean> index_opt_unique opt_verbose opt_full
 %type <boolean> opt_freeze opt_default opt_recheck
+%type <boolean>    ColIdGen ColOptIdGen
 %type <defelt>    opt_binary opt_oids copy_delimiter

 %type <boolean> copy_from opt_hold
@@ -284,8 +285,8 @@

 %type <node>    fetch_direction select_limit_value select_offset_value

-%type <list>    OptSeqList
-%type <defelt>    OptSeqElem
+%type <list>    OptSeqList OptSerialSeqList
+%type <defelt>    OptSeqElem OptSerialSeqElem

 %type <istmt>    insert_rest

@@ -313,7 +314,7 @@
 %type <range>    relation_expr_opt_alias
 %type <target>    target_el insert_target_el update_target_el insert_column_item

-%type <typnam>    Typename SimpleTypename ConstTypename
+%type <typnam>    Typename SimpleTypename SerialTypename ConstTypename
                 GenericType Numeric opt_float
                 Character ConstCharacter
                 CharacterWithLength CharacterWithoutLength
@@ -357,10 +358,10 @@

 /* ordinary key words in alphabetical order */
 %token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
-    AGGREGATE ALL ALSO ALTER ANALYSE ANALYZE AND ANY ARRAY AS ASC
+    AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
     ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION

-    BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT
+    BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BIGSERIAL BINARY BIT
     BOOLEAN_P BOTH BY

     CACHE CALLED CASCADE CASCADED CASE CAST CHAIN CHAR_P
@@ -380,11 +381,11 @@
     FALSE_P FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
     FREEZE FROM FULL FUNCTION

-    GLOBAL GRANT GRANTED GREATEST GROUP_P
+    GENERATED GLOBAL GRANT GRANTED GREATEST GROUP_P

     HANDLER HAVING HEADER_P HOLD HOUR_P

-    IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT
+    IDENTITY IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT
     INDEX INHERIT INHERITS INITIALLY INNER_P INOUT INPUT_P
     INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT
     INTERVAL INTO INVOKER IS ISNULL ISOLATION
@@ -417,7 +418,7 @@
     ROLE ROLLBACK ROW ROWS RULE

     SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE
-    SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
+    SERIAL SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
     SHOW SIMILAR SIMPLE SMALLINT SOME STABLE START STATEMENT
     STATISTICS STDIN STDOUT STORAGE STRICT_P SUBSTRING SUPERUSER_P SYMMETRIC
     SYSID SYSTEM_P
@@ -1798,17 +1799,83 @@
             | TableConstraint                    { $$ = $1; }
         ;

-columnDef:    ColId Typename ColQualList
+/*
+ * SERIAL is special, handle it here. Possible cases:
+ * ColID SERIAL
+ * ColID SERIAL GENERATED {ALWAYS | BY DEFAULT}
+ * ColID SERIAL GENERATED [ALWAYS | BY DEFAULT] AS IDENTITY(...)
+ */
+columnDef:    ColId SerialTypename GENERATED ColOptIdGen AS IDENTITY '(' OptSerialSeqList ')' ColQualList
+                {
+                    ColumnDef *n = makeNode(ColumnDef);
+                    n->colname = $1;
+                    n->typename = $2;
+                    n->constraints = $10;
+                    n->is_local = true;
+                    n->is_serial = true;
+                    n->force_default = $4;
+                    n->seq_opts = $8;
+                    $$ = (Node *)n;
+                }
+            | ColId SerialTypename GENERATED ColIdGen ColQualList
+                {
+                    ColumnDef *n = makeNode(ColumnDef);
+                    n->colname = $1;
+                    n->typename = $2;
+                    n->constraints = $5;
+                    n->is_local = true;
+                    n->is_serial = true;
+                    n->force_default = $4;
+                    n->seq_opts = NIL;
+                    $$ = (Node *)n;
+                }
+            | ColId SerialTypename ColQualList
+                {
+                    ColumnDef *n = makeNode(ColumnDef);
+                    n->colname = $1;
+                    n->typename = $2;
+                    n->constraints = $3;
+                    n->is_local = true;
+                    n->is_serial = true;
+                    n->force_default = false;
+                    n->seq_opts = NIL;
+                    $$ = (Node *)n;
+                }
+            | ColId Typename ColQualList
                 {
                     ColumnDef *n = makeNode(ColumnDef);
                     n->colname = $1;
                     n->typename = $2;
                     n->constraints = $3;
                     n->is_local = true;
+                    n->is_serial = false;
+                    n->force_default = false;
+                    n->seq_opts = NIL;
                     $$ = (Node *)n;
                 }
         ;

+SerialTypename:    SERIAL
+                {
+                    $$ = SystemTypeName("int4");
+                }
+            | BIGSERIAL
+                {
+                    $$ = SystemTypeName("int8");
+                }
+        ;
+
+ColOptIdGen:
+        ALWAYS                                        { $$ = true; }
+            | BY DEFAULT                                { $$ = false; }
+            | /*EMPTY*/                                { $$ = false; }
+        ;
+
+ColIdGen:
+        ALWAYS                                        { $$ = true; }
+            | BY DEFAULT                                { $$ = false; }
+        ;
+
 ColQualList:
             ColQualList ColConstraint                { $$ = lappend($1, $2); }
             | /*EMPTY*/                                { $$ = NIL; }
@@ -2319,6 +2386,48 @@
                 }
         ;

+OptSerialSeqList: OptSerialSeqList OptSerialSeqElem                    { $$ = lappend($1, $2); }
+            | /*EMPTY*/                                { $$ = NIL; }
+        ;
+
+OptSerialSeqElem: CYCLE
+                {
+                    $$ = makeDefElem("cycle", (Node *)makeInteger(TRUE));
+                }
+            | NO CYCLE
+                {
+                    $$ = makeDefElem("cycle", (Node *)makeInteger(FALSE));
+                }
+            | INCREMENT opt_by NumericOnly
+                {
+                    $$ = makeDefElem("increment", (Node *)$3);
+                }
+            | MAXVALUE NumericOnly
+                {
+                    $$ = makeDefElem("maxvalue", (Node *)$2);
+                }
+            | MINVALUE NumericOnly
+                {
+                    $$ = makeDefElem("minvalue", (Node *)$2);
+                }
+            | NO MAXVALUE
+                {
+                    $$ = makeDefElem("maxvalue", NULL);
+                }
+            | NO MINVALUE
+                {
+                    $$ = makeDefElem("minvalue", NULL);
+                }
+            | START opt_with NumericOnly
+                {
+                    $$ = makeDefElem("start", (Node *)$3);
+                }
+            | RESTART opt_with NumericOnly
+                {
+                    $$ = makeDefElem("restart", (Node *)$3);
+                }
+        ;
+
 opt_by:        BY                {}
             | /* empty */    {}
       ;
@@ -8349,6 +8458,7 @@
             | AGGREGATE
             | ALSO
             | ALTER
+            | ALWAYS
             | ASSERTION
             | ASSIGNMENT
             | AT
@@ -8408,6 +8518,7 @@
             | FORCE
             | FORWARD
             | FUNCTION
+            | GENERATED
             | GLOBAL
             | GRANTED
             | HANDLER
@@ -8561,6 +8672,7 @@
  */
 col_name_keyword:
               BIGINT
+            | BIGSERIAL
             | BIT
             | BOOLEAN_P
             | CHAR_P
@@ -8589,6 +8701,7 @@
             | PRECISION
             | REAL
             | ROW
+            | SERIAL
             | SETOF
             | SMALLINT
             | SUBSTRING
@@ -8676,6 +8789,7 @@
             | GRANT
             | GROUP_P
             | HAVING
+            | IDENTITY
             | IN_P
             | INITIALLY
             | INTERSECT
diff -ur postgresql-8.2/src/backend/parser/keywords.c postgresql-8.2-serial/src/backend/parser/keywords.c
--- postgresql-8.2/src/backend/parser/keywords.c    2006-03-05 16:58:32.000000000 +0100
+++ postgresql-8.2-serial/src/backend/parser/keywords.c    2006-06-11 23:29:39.000000000 +0200
@@ -41,6 +41,7 @@
     {"all", ALL},
     {"also", ALSO},
     {"alter", ALTER},
+    {"always", ALWAYS},
     {"analyse", ANALYSE},        /* British spelling */
     {"analyze", ANALYZE},
     {"and", AND},
@@ -58,6 +59,7 @@
     {"begin", BEGIN_P},
     {"between", BETWEEN},
     {"bigint", BIGINT},
+    {"bigserial", BIGSERIAL},
     {"binary", BINARY},
     {"bit", BIT},
     {"boolean", BOOLEAN_P},
@@ -150,6 +152,7 @@
     {"from", FROM},
     {"full", FULL},
     {"function", FUNCTION},
+    {"generated", GENERATED},
     {"global", GLOBAL},
     {"grant", GRANT},
     {"granted", GRANTED},
@@ -160,6 +163,7 @@
     {"header", HEADER_P},
     {"hold", HOLD},
     {"hour", HOUR_P},
+    {"identity", IDENTITY},
     {"if", IF_P},
     {"ilike", ILIKE},
     {"immediate", IMMEDIATE},
@@ -297,6 +301,9 @@
     {"security", SECURITY},
     {"select", SELECT},
     {"sequence", SEQUENCE},
+    {"serial", SERIAL},
+    {"serial4", SERIAL},
+    {"serial8", BIGSERIAL},
     {"serializable", SERIALIZABLE},
     {"session", SESSION},
     {"session_user", SESSION_USER},
diff -ur postgresql-8.2/src/include/nodes/parsenodes.h postgresql-8.2-serial/src/include/nodes/parsenodes.h
--- postgresql-8.2/src/include/nodes/parsenodes.h    2006-04-30 20:30:40.000000000 +0200
+++ postgresql-8.2-serial/src/include/nodes/parsenodes.h    2006-06-11 23:37:15.000000000 +0200
@@ -394,6 +394,9 @@
     char       *cooked_default; /* nodeToString representation */
     List       *constraints;    /* other constraints on column */
     RangeVar   *support;        /* supporting relation, if any */
+    bool        is_serial;    /* the column is SERIAL */
+    bool        force_default;    /* the column is SERIAL GENERATED ALWAYS */
+    List       *seq_opts;        /* the column is SERIAL ... AS IDENTITY(...) */
 } ColumnDef;

 /*

pgsql-hackers by date:

Previous
From: "Marc G. Fournier"
Date:
Subject: Re: postgresql and process titles
Next
From: Rod Taylor
Date:
Subject: Re: Extended SERIAL parsing