Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 3217327

Browse files
committed
Identity columns
This is the SQL standard-conforming variant of PostgreSQL's serial columns. It fixes a few usability issues that serial columns have: - CREATE TABLE / LIKE copies default but refers to same sequence - cannot add/drop serialness with ALTER TABLE - dropping default does not drop sequence - need to grant separate privileges to sequence - other slight weirdnesses because serial is some kind of special macro Reviewed-by: Vitaly Burovoy <vitaly.burovoy@gmail.com>
1 parent 6bad580 commit 3217327

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+2140
-202
lines changed

doc/src/sgml/catalogs.sgml

+11
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,17 @@
11291129
</entry>
11301130
</row>
11311131

1132+
<row>
1133+
<entry><structfield>attidentity</structfield></entry>
1134+
<entry><type>char</type></entry>
1135+
<entry></entry>
1136+
<entry>
1137+
If a zero byte (<literal>''</literal>), then not an identity column.
1138+
Otherwise, <literal>a</literal> = generated
1139+
always, <literal>d</literal> = generated by default.
1140+
</entry>
1141+
</row>
1142+
11321143
<row>
11331144
<entry><structfield>attisdropped</structfield></entry>
11341145
<entry><type>bool</type></entry>

doc/src/sgml/information_schema.sgml

+9-2
Original file line numberDiff line numberDiff line change
@@ -1583,13 +1583,20 @@
15831583
<row>
15841584
<entry><literal>is_identity</literal></entry>
15851585
<entry><type>yes_or_no</type></entry>
1586-
<entry>Applies to a feature not available in <productname>PostgreSQL</></entry>
1586+
<entry>
1587+
If the column is an identity column, then <literal>YES</literal>,
1588+
else <literal>NO</literal>.
1589+
</entry>
15871590
</row>
15881591

15891592
<row>
15901593
<entry><literal>identity_generation</literal></entry>
15911594
<entry><type>character_data</type></entry>
1592-
<entry>Applies to a feature not available in <productname>PostgreSQL</></entry>
1595+
<entry>
1596+
If the column is an identity column, then <literal>ALWAYS</literal>
1597+
or <literal>BY DEFAULT</literal>, reflecting the definition of the
1598+
column.
1599+
</entry>
15931600
</row>
15941601

15951602
<row>

doc/src/sgml/ref/alter_table.sgml

+43-4
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ ALTER TABLE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable>
4646
ALTER [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> SET DEFAULT <replaceable class="PARAMETER">expression</replaceable>
4747
ALTER [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> DROP DEFAULT
4848
ALTER [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> { SET | DROP } NOT NULL
49+
ALTER [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( <replaceable>sequence_options</replaceable> ) ]
50+
ALTER [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> { SET GENERATED { ALWAYS | BY DEFAULT } | SET <replaceable>sequence_option</replaceable> | RESTART [ [ WITH ] <replaceable class="parameter">restart</replaceable> ] } [...]
51+
ALTER [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> DROP IDENTITY [ IF EXISTS ]
4952
ALTER [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> SET STATISTICS <replaceable class="PARAMETER">integer</replaceable>
5053
ALTER [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> SET ( <replaceable class="PARAMETER">attribute_option</replaceable> = <replaceable class="PARAMETER">value</replaceable> [, ... ] )
5154
ALTER [ COLUMN ] <replaceable class="PARAMETER">column_name</replaceable> RESET ( <replaceable class="PARAMETER">attribute_option</replaceable> [, ... ] )
@@ -187,6 +190,38 @@ ALTER TABLE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable>
187190
</listitem>
188191
</varlistentry>
189192

193+
<varlistentry>
194+
<term><literal>ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY</literal></term>
195+
<term><literal>SET GENERATED { ALWAYS | BY DEFAULT }</literal></term>
196+
<term><literal>DROP IDENTITY [ IF EXISTS ]</literal></term>
197+
<listitem>
198+
<para>
199+
These forms change whether a column is an identity column or change the
200+
generation attribute of an existing identity column.
201+
See <xref linkend="sql-createtable"> for details.
202+
</para>
203+
204+
<para>
205+
If <literal>DROP IDENTITY IF EXISTS</literal> is specified and the
206+
column is not an identity column, no error is thrown. In this case a
207+
notice is issued instead.
208+
</para>
209+
</listitem>
210+
</varlistentry>
211+
212+
<varlistentry>
213+
<term><literal>SET <replaceable>sequence_option</replaceable></literal></term>
214+
<term><literal>RESTART</literal></term>
215+
<listitem>
216+
<para>
217+
These forms alter the sequence that underlies an existing identity
218+
column. <replaceable>sequence_option</replaceable> is an option
219+
supported by <xref linkend="sql-altersequence"> such
220+
as <literal>INCREMENT BY</literal>.
221+
</para>
222+
</listitem>
223+
</varlistentry>
224+
190225
<varlistentry>
191226
<term><literal>SET STATISTICS</literal></term>
192227
<listitem>
@@ -1160,8 +1195,11 @@ ALTER TABLE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable>
11601195
</para>
11611196

11621197
<para>
1163-
The <literal>TRIGGER</>, <literal>CLUSTER</>, <literal>OWNER</>,
1164-
and <literal>TABLESPACE</> actions never recurse to descendant tables;
1198+
The actions for identity columns (<literal>ADD
1199+
GENERATED</literal>, <literal>SET</literal> etc., <literal>DROP
1200+
IDENTITY</literal>), as well as the actions
1201+
<literal>TRIGGER</>, <literal>CLUSTER</>, <literal>OWNER</>,
1202+
and <literal>TABLESPACE</> never recurse to descendant tables;
11651203
that is, they always act as though <literal>ONLY</> were specified.
11661204
Adding a constraint recurses only for <literal>CHECK</> constraints
11671205
that are not marked <literal>NO INHERIT</>.
@@ -1371,8 +1409,9 @@ ALTER TABLE cities
13711409

13721410
<para>
13731411
The forms <literal>ADD</literal> (without <literal>USING INDEX</literal>),
1374-
<literal>DROP</>, <literal>SET DEFAULT</>,
1375-
and <literal>SET DATA TYPE</literal> (without <literal>USING</literal>)
1412+
<literal>DROP [COLUMN]</>, <literal>DROP IDENTITY</literal>, <literal>RESTART</literal>,
1413+
<literal>SET DEFAULT</>, <literal>SET DATA TYPE</literal> (without <literal>USING</literal>),
1414+
<literal>SET GENERATED</literal>, and <literal>SET <replaceable>sequence_option</replaceable></literal>
13761415
conform with the SQL standard. The other forms are
13771416
<productname>PostgreSQL</productname> extensions of the SQL standard.
13781417
Also, the ability to specify more than one manipulation in a single

doc/src/sgml/ref/copy.sgml

+7
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,13 @@ COPY <replaceable class="parameter">count</replaceable>
479479
constraints on the destination table. However, it will not invoke rules.
480480
</para>
481481

482+
<para>
483+
For identity columns, the <command>COPY FROM</command> command will always
484+
write the column values provided in the input data, like
485+
the <command>INPUT</command> option <literal>OVERRIDING SYSTEM
486+
VALUE</literal>.
487+
</para>
488+
482489
<para>
483490
<command>COPY</command> input and output is affected by
484491
<varname>DateStyle</varname>. To ensure portability to other

doc/src/sgml/ref/create_table.sgml

+61-4
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
6262
NULL |
6363
CHECK ( <replaceable class="PARAMETER">expression</replaceable> ) [ NO INHERIT ] |
6464
DEFAULT <replaceable>default_expr</replaceable> |
65+
GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( <replaceable>sequence_options</replaceable> ) ] |
6566
UNIQUE <replaceable class="PARAMETER">index_parameters</replaceable> |
6667
PRIMARY KEY <replaceable class="PARAMETER">index_parameters</replaceable> |
6768
REFERENCES <replaceable class="PARAMETER">reftable</replaceable> [ ( <replaceable class="PARAMETER">refcolumn</replaceable> ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ]
@@ -81,7 +82,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
8182

8283
<phrase>and <replaceable class="PARAMETER">like_option</replaceable> is:</phrase>
8384

84-
{ INCLUDING | EXCLUDING } { DEFAULTS | CONSTRAINTS | INDEXES | STORAGE | COMMENTS | ALL }
85+
{ INCLUDING | EXCLUDING } { DEFAULTS | CONSTRAINTS | IDENTITY | INDEXES | STORAGE | COMMENTS | ALL }
8586

8687
<phrase>and <replaceable class="PARAMETER">partition_bound_spec</replaceable> is:</phrase>
8788

@@ -412,6 +413,11 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
412413
Column <literal>STORAGE</> settings are also copied from parent tables.
413414
</para>
414415

416+
<para>
417+
If a column in the parent table is an identity column, that property is
418+
not inherited. A column in the child table can be declared identity
419+
column if desired.
420+
</para>
415421
</listitem>
416422
</varlistentry>
417423

@@ -480,6 +486,12 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
480486
such as <function>nextval</>, may create a functional linkage between
481487
the original and new tables.
482488
</para>
489+
<para>
490+
Any identity specifications of copied column definitions will only be
491+
copied if <literal>INCLUDING IDENTITY</literal> is specified. A new
492+
sequence is created for each identity column of the new table, separate
493+
from the sequences associated with the old table.
494+
</para>
483495
<para>
484496
Not-null constraints are always copied to the new table.
485497
<literal>CHECK</literal> constraints will be copied only if
@@ -512,7 +524,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
512524
</para>
513525
<para>
514526
<literal>INCLUDING ALL</literal> is an abbreviated form of
515-
<literal>INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING STORAGE INCLUDING COMMENTS</literal>.
527+
<literal>INCLUDING DEFAULTS INCLUDING IDENTITY INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING STORAGE INCLUDING COMMENTS</literal>.
516528
</para>
517529
<para>
518530
Note that unlike <literal>INHERITS</literal>, columns and
@@ -626,6 +638,37 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
626638
</listitem>
627639
</varlistentry>
628640

641+
<varlistentry>
642+
<term><literal>GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( <replaceable>sequence_options</replaceable> ) ]</literal></term>
643+
<listitem>
644+
<para>
645+
This clause creates the column as an <firstterm>identity
646+
column</firstterm>. It will have an implicit sequence attached to it
647+
and the column in new rows will automatically have values from the
648+
sequence assigned to it.
649+
</para>
650+
651+
<para>
652+
The clauses <literal>ALWAYS</literal> and <literal>BY DEFAULT</literal>
653+
determine how the sequence value is given precedence over a
654+
user-specified value in an <command>INSERT</command> statement.
655+
If <literal>ALWAYS</literal> is specified, a user-specified value is
656+
only accepted if the <command>INSERT</command> statement
657+
specifies <literal>OVERRIDING SYSTEM VALUE</literal>. If <literal>BY
658+
DEFAULT</literal> is specified, then the user-specified value takes
659+
precedence. See <xref linkend="sql-insert"> for details. (In
660+
the <command>COPY</command> command, user-specified values are always
661+
used regardless of this setting.)
662+
</para>
663+
664+
<para>
665+
The optional <replaceable>sequence_options</replaceable> clause can be
666+
used to override the options of the sequence.
667+
See <xref linkend="sql-createsequence"> for details.
668+
</para>
669+
</listitem>
670+
</varlistentry>
671+
629672
<varlistentry>
630673
<term><literal>UNIQUE</> (column constraint)</term>
631674
<term><literal>UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] )</> (table constraint)</term>
@@ -1263,7 +1306,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
12631306

12641307
<para>
12651308
Using OIDs in new applications is not recommended: where
1266-
possible, using a <literal>SERIAL</literal> or other sequence
1309+
possible, using an identity column or other sequence
12671310
generator as the table's primary key is preferred. However, if
12681311
your application does make use of OIDs to identify specific
12691312
rows of a table, it is recommended to create a unique constraint
@@ -1323,7 +1366,7 @@ CREATE TABLE films (
13231366
);
13241367

13251368
CREATE TABLE distributors (
1326-
did integer PRIMARY KEY DEFAULT nextval('serial'),
1369+
did integer PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
13271370
name varchar(40) NOT NULL CHECK (name &lt;&gt; '')
13281371
);
13291372
</programlisting>
@@ -1737,6 +1780,20 @@ CREATE TABLE cities_ab_10000_to_100000
17371780
</para>
17381781
</refsect2>
17391782

1783+
<refsect2>
1784+
<title>Multiple Identity Columns</title>
1785+
1786+
<para>
1787+
<productname>PostgreSQL</productname> allows a table to have more than one
1788+
identity column. The standard specifies that a table can have at most one
1789+
identity column. This is relaxed mainly to give more flexibility for
1790+
doing schema changes or migrations. Note that
1791+
the <command>INSERT</command> command supports only one override clause
1792+
that applies to the entire statement, so having multiple identity columns
1793+
with different behaviors is not well supported.
1794+
</para>
1795+
</refsect2>
1796+
17401797
<refsect2>
17411798
<title><literal>LIKE</> Clause</title>
17421799

doc/src/sgml/ref/insert.sgml

+41
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ PostgreSQL documentation
2323
<synopsis>
2424
[ WITH [ RECURSIVE ] <replaceable class="parameter">with_query</replaceable> [, ...] ]
2525
INSERT INTO <replaceable class="PARAMETER">table_name</replaceable> [ AS <replaceable class="parameter">alias</replaceable> ] [ ( <replaceable class="PARAMETER">column_name</replaceable> [, ...] ) ]
26+
[ OVERRIDING { SYSTEM | USER} VALUE ]
2627
{ DEFAULT VALUES | VALUES ( { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] ) [, ...] | <replaceable class="PARAMETER">query</replaceable> }
2728
[ ON CONFLICT [ <replaceable class="parameter">conflict_target</replaceable> ] <replaceable class="parameter">conflict_action</replaceable> ]
2829
[ RETURNING * | <replaceable class="parameter">output_expression</replaceable> [ [ AS ] <replaceable class="parameter">output_name</replaceable> ] [, ...] ]
@@ -201,11 +202,44 @@ INSERT INTO <replaceable class="PARAMETER">table_name</replaceable> [ AS <replac
201202
</listitem>
202203
</varlistentry>
203204

205+
<varlistentry>
206+
<term><literal>OVERRIDING SYSTEM VALUE</literal></term>
207+
<listitem>
208+
<para>
209+
Without this clause, it is an error to specify an explicit value
210+
(other than <literal>DEFAULT</literal>) for an identity column defined
211+
as <literal>GENERATED ALWAYS</literal>. This clause overrides that
212+
restriction.
213+
</para>
214+
</listitem>
215+
</varlistentry>
216+
217+
<varlistentry>
218+
<term><literal>OVERRIDING USER VALUE</literal></term>
219+
<listitem>
220+
<para>
221+
If this clause is specified, then any values supplied for identity
222+
columns defined as <literal>GENERATED BY DEFAULT</literal> are ignored
223+
and the default sequence-generated values are applied.
224+
</para>
225+
226+
<para>
227+
This clause is useful for example when copying values between tables.
228+
Writing <literal>INSERT INTO tbl2 OVERRIDING USER VALUE SELECT * FROM
229+
tbl1</literal> will copy from <literal>tbl1</literal> all columns that
230+
are not identity columns in <literal>tbl2</literal> but will continue
231+
the sequence counters for any identity columns.
232+
</para>
233+
</listitem>
234+
</varlistentry>
235+
204236
<varlistentry>
205237
<term><literal>DEFAULT VALUES</literal></term>
206238
<listitem>
207239
<para>
208240
All columns will be filled with their default values.
241+
(An <literal>OVERRIDING</literal> clause is not permitted in this
242+
form.)
209243
</para>
210244
</listitem>
211245
</varlistentry>
@@ -710,6 +744,13 @@ INSERT INTO distributors (did, dname) VALUES (10, 'Conrad International')
710744
is disallowed by the standard.
711745
</para>
712746

747+
<para>
748+
The SQL standard specifies that <literal>OVERRIDING SYSTEM VALUE</literal>
749+
can only be specified if an identity column that is generated always
750+
exists. PostgreSQL allows the clause in any case and ignores it if it is
751+
not applicable.
752+
</para>
753+
713754
<para>
714755
Possible limitations of the <replaceable
715756
class="PARAMETER">query</replaceable> clause are documented under

src/backend/access/common/tupdesc.c

+6
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ CreateTupleDescCopy(TupleDesc tupdesc)
150150
memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
151151
desc->attrs[i]->attnotnull = false;
152152
desc->attrs[i]->atthasdef = false;
153+
desc->attrs[i]->attidentity = '\0';
153154
}
154155

155156
desc->tdtypeid = tupdesc->tdtypeid;
@@ -257,6 +258,7 @@ TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno,
257258
/* since we're not copying constraints or defaults, clear these */
258259
dst->attrs[dstAttno - 1]->attnotnull = false;
259260
dst->attrs[dstAttno - 1]->atthasdef = false;
261+
dst->attrs[dstAttno - 1]->attidentity = '\0';
260262
}
261263

262264
/*
@@ -401,6 +403,8 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
401403
return false;
402404
if (attr1->atthasdef != attr2->atthasdef)
403405
return false;
406+
if (attr1->attidentity != attr2->attidentity)
407+
return false;
404408
if (attr1->attisdropped != attr2->attisdropped)
405409
return false;
406410
if (attr1->attislocal != attr2->attislocal)
@@ -534,6 +538,7 @@ TupleDescInitEntry(TupleDesc desc,
534538

535539
att->attnotnull = false;
536540
att->atthasdef = false;
541+
att->attidentity = '\0';
537542
att->attisdropped = false;
538543
att->attislocal = true;
539544
att->attinhcount = 0;
@@ -591,6 +596,7 @@ TupleDescInitBuiltinEntry(TupleDesc desc,
591596

592597
att->attnotnull = false;
593598
att->atthasdef = false;
599+
att->attidentity = '\0';
594600
att->attisdropped = false;
595601
att->attislocal = true;
596602
att->attinhcount = 0;

src/backend/catalog/dependency.c

+7
Original file line numberDiff line numberDiff line change
@@ -1929,6 +1929,13 @@ find_expr_references_walker(Node *node,
19291929
context->addrs);
19301930
/* fall through to examine arguments */
19311931
}
1932+
else if (IsA(node, NextValueExpr))
1933+
{
1934+
NextValueExpr *nve = (NextValueExpr *) node;
1935+
1936+
add_object_address(OCLASS_CLASS, nve->seqid, 0,
1937+
context->addrs);
1938+
}
19321939

19331940
return expression_tree_walker(node, find_expr_references_walker,
19341941
(void *) context);

0 commit comments

Comments
 (0)