@@ -43,6 +43,7 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
4343 ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> RESET ( <replaceable class="PARAMETER">attribute_option</replaceable> [, ... ] )
4444 ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN }
4545 ADD <replaceable class="PARAMETER">table_constraint</replaceable>
46+ ADD <replaceable class="PARAMETER">table_constraint_using_index</replaceable>
4647 DROP CONSTRAINT [ IF EXISTS ] <replaceable class="PARAMETER">constraint_name</replaceable> [ RESTRICT | CASCADE ]
4748 DISABLE TRIGGER [ <replaceable class="PARAMETER">trigger_name</replaceable> | ALL | USER ]
4849 ENABLE TRIGGER [ <replaceable class="PARAMETER">trigger_name</replaceable> | ALL | USER ]
@@ -62,6 +63,12 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
6263 NO INHERIT <replaceable class="PARAMETER">parent_table</replaceable>
6364 OWNER TO <replaceable class="PARAMETER">new_owner</replaceable>
6465 SET TABLESPACE <replaceable class="PARAMETER">new_tablespace</replaceable>
66+
67+ <phrase>and <replaceable class="PARAMETER">table_constraint_using_index</replaceable> is:</phrase>
68+
69+ [ CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ]
70+ { UNIQUE | PRIMARY KEY } USING INDEX <replaceable class="PARAMETER">index_name</replaceable>
71+ [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
6572</synopsis>
6673 </refsynopsisdiv>
6774
@@ -229,6 +236,57 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
229236 </listitem>
230237 </varlistentry>
231238
239+ <varlistentry>
240+ <term><literal>ADD <replaceable class="PARAMETER">table_constraint_using_index</replaceable></literal></term>
241+ <listitem>
242+ <para>
243+ This form adds a new <literal>PRIMARY KEY</> or <literal>UNIQUE</>
244+ constraint to a table based on an existing unique index. All the
245+ columns of the index will be included in the constraint.
246+ </para>
247+
248+ <para>
249+ The index cannot have expression columns nor be a partial index.
250+ Also, it must be a b-tree index with default sort ordering. These
251+ restrictions ensure that the index is equivalent to one that would be
252+ built by a regular <literal>ADD PRIMARY KEY</> or <literal>ADD UNIQUE</>
253+ command.
254+ </para>
255+
256+ <para>
257+ If <literal>PRIMARY KEY</> is specified, and the index's columns are not
258+ already marked <literal>NOT NULL</>, then this command will attempt to
259+ do <literal>ALTER COLUMN SET NOT NULL</> against each such column.
260+ That requires a full table scan to verify the column(s) contain no
261+ nulls. In all other cases, this is a fast operation.
262+ </para>
263+
264+ <para>
265+ If a constraint name is provided then the index will be renamed to match
266+ the constraint name. Otherwise the constraint will be named the same as
267+ the index.
268+ </para>
269+
270+ <para>
271+ After this command is executed, the index is <quote>owned</> by the
272+ constraint, in the same way as if the index had been built by
273+ a regular <literal>ADD PRIMARY KEY</> or <literal>ADD UNIQUE</>
274+ command. In particular, dropping the constraint will make the index
275+ disappear too.
276+ </para>
277+
278+ <note>
279+ <para>
280+ Adding a constraint using an existing index can be helpful in
281+ situations where a new constraint needs to be added without blocking
282+ table updates for a long time. To do that, create the index using
283+ <command>CREATE INDEX CONCURRENTLY</>, and then install it as an
284+ official constraint using this syntax. See the example below.
285+ </para>
286+ </note>
287+ </listitem>
288+ </varlistentry>
289+
232290 <varlistentry>
233291 <term><literal>DROP CONSTRAINT [ IF EXISTS ]</literal></term>
234292 <listitem>
@@ -920,13 +978,24 @@ ALTER TABLE myschema.distributors SET SCHEMA yourschema;
920978</programlisting>
921979 </para>
922980
981+ <para>
982+ To recreate a primary key constraint, without blocking updates while the
983+ index is rebuilt:
984+ <programlisting>
985+ CREATE UNIQUE INDEX CONCURRENTLY dist_id_temp_idx on distributors (dist_id);
986+ ALTER TABLE distributors DROP CONSTRAINT distributors_pkey,
987+ ADD CONSTRAINT distributors_pkey PRIMARY KEY USING INDEX dist_id_temp_idx;
988+ </programlisting>
989+ </para>
990+
923991 </refsect1>
924992
925993 <refsect1>
926994 <title>Compatibility</title>
927995
928996 <para>
929- The forms <literal>ADD</literal>, <literal>DROP</>, <literal>SET DEFAULT</>,
997+ The forms <literal>ADD</literal> (without <literal>USING INDEX</literal>),
998+ <literal>DROP</>, <literal>SET DEFAULT</>,
930999 and <literal>SET DATA TYPE</literal> (without <literal>USING</literal>)
9311000 conform with the SQL standard. The other forms are
9321001 <productname>PostgreSQL</productname> extensions of the SQL standard.
@@ -940,4 +1009,12 @@ ALTER TABLE myschema.distributors SET SCHEMA yourschema;
9401009 extension of SQL, which disallows zero-column tables.
9411010 </para>
9421011 </refsect1>
1012+
1013+ <refsect1>
1014+ <title>See Also</title>
1015+
1016+ <simplelist type="inline">
1017+ <member><xref linkend="sql-createtable"></member>
1018+ </simplelist>
1019+ </refsect1>
9431020</refentry>
0 commit comments