Skip to content

Commit 08309aa

Browse files
committed
Implement IF NOT EXIST for CREATE INDEX.
Fabrízio de Royes Mello, reviewed by Marti Raudsepp, Adam Brightwell and me.
1 parent 171c377 commit 08309aa

File tree

11 files changed

+85
-5
lines changed

11 files changed

+85
-5
lines changed

doc/src/sgml/ref/create_index.sgml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ PostgreSQL documentation
2121

2222
<refsynopsisdiv>
2323
<synopsis>
24-
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ <replaceable class="parameter">name</replaceable> ] ON <replaceable class="parameter">table_name</replaceable> [ USING <replaceable class="parameter">method</replaceable> ]
24+
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> ] ON <replaceable class="parameter">table_name</replaceable> [ USING <replaceable class="parameter">method</replaceable> ]
2525
( { <replaceable class="parameter">column_name</replaceable> | ( <replaceable class="parameter">expression</replaceable> ) } [ COLLATE <replaceable class="parameter">collation</replaceable> ] [ <replaceable class="parameter">opclass</replaceable> ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] )
2626
[ WITH ( <replaceable class="PARAMETER">storage_parameter</replaceable> = <replaceable class="PARAMETER">value</replaceable> [, ... ] ) ]
2727
[ TABLESPACE <replaceable class="parameter">tablespace_name</replaceable> ]
@@ -126,6 +126,18 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ <replaceable class="parameter">name</
126126
</listitem>
127127
</varlistentry>
128128

129+
<varlistentry>
130+
<term><literal>IF NOT EXISTS</literal></term>
131+
<listitem>
132+
<para>
133+
Do not throw an error if a relation with the same name already exists.
134+
A notice is issued in this case. Note that there is no guarantee that
135+
the existing index is anything like the one that would have been created.
136+
Index name is required when <literal>IF NOT EXISTS</literal> is specified.
137+
</para>
138+
</listitem>
139+
</varlistentry>
140+
129141
<varlistentry>
130142
<term><replaceable class="parameter">name</replaceable></term>
131143
<listitem>

src/backend/catalog/index.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,8 @@ UpdateIndexRelation(Oid indexoid,
674674
* will be marked "invalid" and the caller must take additional steps
675675
* to fix it up.
676676
* is_internal: if true, post creation hook for new index
677+
* if_not_exists: if true, do not throw an error if a relation with
678+
* the same name already exists.
677679
*
678680
* Returns the OID of the created index.
679681
*/
@@ -697,7 +699,8 @@ index_create(Relation heapRelation,
697699
bool allow_system_table_mods,
698700
bool skip_build,
699701
bool concurrent,
700-
bool is_internal)
702+
bool is_internal,
703+
bool if_not_exists)
701704
{
702705
Oid heapRelationId = RelationGetRelid(heapRelation);
703706
Relation pg_class;
@@ -773,10 +776,22 @@ index_create(Relation heapRelation,
773776
elog(ERROR, "shared relations must be placed in pg_global tablespace");
774777

775778
if (get_relname_relid(indexRelationName, namespaceId))
779+
{
780+
if (if_not_exists)
781+
{
782+
ereport(NOTICE,
783+
(errcode(ERRCODE_DUPLICATE_TABLE),
784+
errmsg("relation \"%s\" already exists, skipping",
785+
indexRelationName)));
786+
heap_close(pg_class, RowExclusiveLock);
787+
return InvalidOid;
788+
}
789+
776790
ereport(ERROR,
777791
(errcode(ERRCODE_DUPLICATE_TABLE),
778792
errmsg("relation \"%s\" already exists",
779793
indexRelationName)));
794+
}
780795

781796
/*
782797
* construct tuple descriptor for index tuples

src/backend/catalog/toasting.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
342342
rel->rd_rel->reltablespace,
343343
collationObjectId, classObjectId, coloptions, (Datum) 0,
344344
true, false, false, false,
345-
true, false, false, true);
345+
true, false, false, true, false);
346346

347347
heap_close(toast_rel, NoLock);
348348

src/backend/commands/indexcmds.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,14 @@ DefineIndex(Oid relationId,
610610
stmt->isconstraint, stmt->deferrable, stmt->initdeferred,
611611
allowSystemTableMods,
612612
skip_build || stmt->concurrent,
613-
stmt->concurrent, !check_rights);
613+
stmt->concurrent, !check_rights,
614+
stmt->if_not_exists);
615+
616+
if (!OidIsValid(indexRelationId))
617+
{
618+
heap_close(rel, NoLock);
619+
return indexRelationId;
620+
}
614621

615622
/* Add any requested comment */
616623
if (stmt->idxcomment != NULL)

src/backend/nodes/copyfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2907,6 +2907,7 @@ _copyIndexStmt(const IndexStmt *from)
29072907
COPY_SCALAR_FIELD(deferrable);
29082908
COPY_SCALAR_FIELD(initdeferred);
29092909
COPY_SCALAR_FIELD(concurrent);
2910+
COPY_SCALAR_FIELD(if_not_exists);
29102911

29112912
return newnode;
29122913
}

src/backend/nodes/equalfuncs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,7 @@ _equalIndexStmt(const IndexStmt *a, const IndexStmt *b)
12101210
COMPARE_SCALAR_FIELD(deferrable);
12111211
COMPARE_SCALAR_FIELD(initdeferred);
12121212
COMPARE_SCALAR_FIELD(concurrent);
1213+
COMPARE_SCALAR_FIELD(if_not_exists);
12131214

12141215
return true;
12151216
}

src/backend/parser/gram.y

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6434,6 +6434,32 @@ IndexStmt: CREATE opt_unique INDEX opt_concurrently opt_index_name
64346434
n->isconstraint = false;
64356435
n->deferrable = false;
64366436
n->initdeferred = false;
6437+
n->if_not_exists = false;
6438+
$$ = (Node *)n;
6439+
}
6440+
| CREATE opt_unique INDEX opt_concurrently IF_P NOT EXISTS index_name
6441+
ON qualified_name access_method_clause '(' index_params ')'
6442+
opt_reloptions OptTableSpace where_clause
6443+
{
6444+
IndexStmt *n = makeNode(IndexStmt);
6445+
n->unique = $2;
6446+
n->concurrent = $4;
6447+
n->idxname = $8;
6448+
n->relation = $10;
6449+
n->accessMethod = $11;
6450+
n->indexParams = $13;
6451+
n->options = $15;
6452+
n->tableSpace = $16;
6453+
n->whereClause = $17;
6454+
n->excludeOpNames = NIL;
6455+
n->idxcomment = NULL;
6456+
n->indexOid = InvalidOid;
6457+
n->oldNode = InvalidOid;
6458+
n->primary = false;
6459+
n->isconstraint = false;
6460+
n->deferrable = false;
6461+
n->initdeferred = false;
6462+
n->if_not_exists = true;
64376463
$$ = (Node *)n;
64386464
}
64396465
;

src/include/catalog/index.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ extern Oid index_create(Relation heapRelation,
6060
bool allow_system_table_mods,
6161
bool skip_build,
6262
bool concurrent,
63-
bool is_internal);
63+
bool is_internal,
64+
bool if_not_exists);
6465

6566
extern void index_constraint_create(Relation heapRelation,
6667
Oid indexRelationId,

src/include/nodes/parsenodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2256,6 +2256,7 @@ typedef struct IndexStmt
22562256
bool deferrable; /* is the constraint DEFERRABLE? */
22572257
bool initdeferred; /* is the constraint INITIALLY DEFERRED? */
22582258
bool concurrent; /* should this be a concurrent index build? */
2259+
bool if_not_exists; /* just do nothing if index already exists? */
22592260
} IndexStmt;
22602261

22612262
/* ----------------------

src/test/regress/expected/create_index.out

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
-- BTREE
77
--
88
CREATE INDEX onek_unique1 ON onek USING btree(unique1 int4_ops);
9+
CREATE INDEX IF NOT EXISTS onek_unique1 ON onek USING btree(unique1 int4_ops);
10+
NOTICE: relation "onek_unique1" already exists, skipping
11+
CREATE INDEX IF NOT EXISTS ON onek USING btree(unique1 int4_ops);
12+
ERROR: syntax error at or near "ON"
13+
LINE 1: CREATE INDEX IF NOT EXISTS ON onek USING btree(unique1 int4_...
14+
^
915
CREATE INDEX onek_unique2 ON onek USING btree(unique2 int4_ops);
1016
CREATE INDEX onek_hundred ON onek USING btree(hundred int4_ops);
1117
CREATE INDEX onek_stringu1 ON onek USING btree(stringu1 name_ops);
@@ -2290,10 +2296,14 @@ create unique index hash_f8_index_3 on hash_f8_heap(random) where seqno > 1000;
22902296
CREATE TABLE concur_heap (f1 text, f2 text);
22912297
-- empty table
22922298
CREATE INDEX CONCURRENTLY concur_index1 ON concur_heap(f2,f1);
2299+
CREATE INDEX CONCURRENTLY IF NOT EXISTS concur_index1 ON concur_heap(f2,f1);
2300+
NOTICE: relation "concur_index1" already exists, skipping
22932301
INSERT INTO concur_heap VALUES ('a','b');
22942302
INSERT INTO concur_heap VALUES ('b','b');
22952303
-- unique index
22962304
CREATE UNIQUE INDEX CONCURRENTLY concur_index2 ON concur_heap(f1);
2305+
CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS concur_index2 ON concur_heap(f1);
2306+
NOTICE: relation "concur_index2" already exists, skipping
22972307
-- check if constraint is set up properly to be enforced
22982308
INSERT INTO concur_heap VALUES ('b','x');
22992309
ERROR: duplicate key value violates unique constraint "concur_index2"

src/test/regress/sql/create_index.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
--
99
CREATE INDEX onek_unique1 ON onek USING btree(unique1 int4_ops);
1010

11+
CREATE INDEX IF NOT EXISTS onek_unique1 ON onek USING btree(unique1 int4_ops);
12+
13+
CREATE INDEX IF NOT EXISTS ON onek USING btree(unique1 int4_ops);
14+
1115
CREATE INDEX onek_unique2 ON onek USING btree(unique2 int4_ops);
1216

1317
CREATE INDEX onek_hundred ON onek USING btree(hundred int4_ops);
@@ -711,10 +715,12 @@ create unique index hash_f8_index_3 on hash_f8_heap(random) where seqno > 1000;
711715
CREATE TABLE concur_heap (f1 text, f2 text);
712716
-- empty table
713717
CREATE INDEX CONCURRENTLY concur_index1 ON concur_heap(f2,f1);
718+
CREATE INDEX CONCURRENTLY IF NOT EXISTS concur_index1 ON concur_heap(f2,f1);
714719
INSERT INTO concur_heap VALUES ('a','b');
715720
INSERT INTO concur_heap VALUES ('b','b');
716721
-- unique index
717722
CREATE UNIQUE INDEX CONCURRENTLY concur_index2 ON concur_heap(f1);
723+
CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS concur_index2 ON concur_heap(f1);
718724
-- check if constraint is set up properly to be enforced
719725
INSERT INTO concur_heap VALUES ('b','x');
720726
-- check if constraint is enforced properly at build time

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy