1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-22 02:52:08 +03:00

Implement IF NOT EXIST for CREATE INDEX.

Fabrízio de Royes Mello, reviewed by Marti Raudsepp, Adam Brightwell and me.
This commit is contained in:
Fujii Masao
2014-11-06 18:48:33 +09:00
parent 171c377a0a
commit 08309aaf74
11 changed files with 85 additions and 5 deletions

View File

@ -21,7 +21,7 @@ PostgreSQL documentation
<refsynopsisdiv> <refsynopsisdiv>
<synopsis> <synopsis>
CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ <replaceable class="parameter">name</replaceable> ] ON <replaceable class="parameter">table_name</replaceable> [ USING <replaceable class="parameter">method</replaceable> ] 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> ]
( { <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 } ] [, ...] ) ( { <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 } ] [, ...] )
[ WITH ( <replaceable class="PARAMETER">storage_parameter</replaceable> = <replaceable class="PARAMETER">value</replaceable> [, ... ] ) ] [ WITH ( <replaceable class="PARAMETER">storage_parameter</replaceable> = <replaceable class="PARAMETER">value</replaceable> [, ... ] ) ]
[ TABLESPACE <replaceable class="parameter">tablespace_name</replaceable> ] [ TABLESPACE <replaceable class="parameter">tablespace_name</replaceable> ]
@ -126,6 +126,18 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ <replaceable class="parameter">name</
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><literal>IF NOT EXISTS</literal></term>
<listitem>
<para>
Do not throw an error if a relation with the same name already exists.
A notice is issued in this case. Note that there is no guarantee that
the existing index is anything like the one that would have been created.
Index name is required when <literal>IF NOT EXISTS</literal> is specified.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><replaceable class="parameter">name</replaceable></term> <term><replaceable class="parameter">name</replaceable></term>
<listitem> <listitem>

View File

@ -674,6 +674,8 @@ UpdateIndexRelation(Oid indexoid,
* will be marked "invalid" and the caller must take additional steps * will be marked "invalid" and the caller must take additional steps
* to fix it up. * to fix it up.
* is_internal: if true, post creation hook for new index * is_internal: if true, post creation hook for new index
* if_not_exists: if true, do not throw an error if a relation with
* the same name already exists.
* *
* Returns the OID of the created index. * Returns the OID of the created index.
*/ */
@ -697,7 +699,8 @@ index_create(Relation heapRelation,
bool allow_system_table_mods, bool allow_system_table_mods,
bool skip_build, bool skip_build,
bool concurrent, bool concurrent,
bool is_internal) bool is_internal,
bool if_not_exists)
{ {
Oid heapRelationId = RelationGetRelid(heapRelation); Oid heapRelationId = RelationGetRelid(heapRelation);
Relation pg_class; Relation pg_class;
@ -773,10 +776,22 @@ index_create(Relation heapRelation,
elog(ERROR, "shared relations must be placed in pg_global tablespace"); elog(ERROR, "shared relations must be placed in pg_global tablespace");
if (get_relname_relid(indexRelationName, namespaceId)) if (get_relname_relid(indexRelationName, namespaceId))
{
if (if_not_exists)
{
ereport(NOTICE,
(errcode(ERRCODE_DUPLICATE_TABLE),
errmsg("relation \"%s\" already exists, skipping",
indexRelationName)));
heap_close(pg_class, RowExclusiveLock);
return InvalidOid;
}
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_TABLE), (errcode(ERRCODE_DUPLICATE_TABLE),
errmsg("relation \"%s\" already exists", errmsg("relation \"%s\" already exists",
indexRelationName))); indexRelationName)));
}
/* /*
* construct tuple descriptor for index tuples * construct tuple descriptor for index tuples

View File

@ -342,7 +342,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
rel->rd_rel->reltablespace, rel->rd_rel->reltablespace,
collationObjectId, classObjectId, coloptions, (Datum) 0, collationObjectId, classObjectId, coloptions, (Datum) 0,
true, false, false, false, true, false, false, false,
true, false, false, true); true, false, false, true, false);
heap_close(toast_rel, NoLock); heap_close(toast_rel, NoLock);

View File

@ -610,7 +610,14 @@ DefineIndex(Oid relationId,
stmt->isconstraint, stmt->deferrable, stmt->initdeferred, stmt->isconstraint, stmt->deferrable, stmt->initdeferred,
allowSystemTableMods, allowSystemTableMods,
skip_build || stmt->concurrent, skip_build || stmt->concurrent,
stmt->concurrent, !check_rights); stmt->concurrent, !check_rights,
stmt->if_not_exists);
if (!OidIsValid(indexRelationId))
{
heap_close(rel, NoLock);
return indexRelationId;
}
/* Add any requested comment */ /* Add any requested comment */
if (stmt->idxcomment != NULL) if (stmt->idxcomment != NULL)

View File

@ -2907,6 +2907,7 @@ _copyIndexStmt(const IndexStmt *from)
COPY_SCALAR_FIELD(deferrable); COPY_SCALAR_FIELD(deferrable);
COPY_SCALAR_FIELD(initdeferred); COPY_SCALAR_FIELD(initdeferred);
COPY_SCALAR_FIELD(concurrent); COPY_SCALAR_FIELD(concurrent);
COPY_SCALAR_FIELD(if_not_exists);
return newnode; return newnode;
} }

View File

@ -1210,6 +1210,7 @@ _equalIndexStmt(const IndexStmt *a, const IndexStmt *b)
COMPARE_SCALAR_FIELD(deferrable); COMPARE_SCALAR_FIELD(deferrable);
COMPARE_SCALAR_FIELD(initdeferred); COMPARE_SCALAR_FIELD(initdeferred);
COMPARE_SCALAR_FIELD(concurrent); COMPARE_SCALAR_FIELD(concurrent);
COMPARE_SCALAR_FIELD(if_not_exists);
return true; return true;
} }

View File

@ -6434,6 +6434,32 @@ IndexStmt: CREATE opt_unique INDEX opt_concurrently opt_index_name
n->isconstraint = false; n->isconstraint = false;
n->deferrable = false; n->deferrable = false;
n->initdeferred = false; n->initdeferred = false;
n->if_not_exists = false;
$$ = (Node *)n;
}
| CREATE opt_unique INDEX opt_concurrently IF_P NOT EXISTS index_name
ON qualified_name access_method_clause '(' index_params ')'
opt_reloptions OptTableSpace where_clause
{
IndexStmt *n = makeNode(IndexStmt);
n->unique = $2;
n->concurrent = $4;
n->idxname = $8;
n->relation = $10;
n->accessMethod = $11;
n->indexParams = $13;
n->options = $15;
n->tableSpace = $16;
n->whereClause = $17;
n->excludeOpNames = NIL;
n->idxcomment = NULL;
n->indexOid = InvalidOid;
n->oldNode = InvalidOid;
n->primary = false;
n->isconstraint = false;
n->deferrable = false;
n->initdeferred = false;
n->if_not_exists = true;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;

View File

@ -60,7 +60,8 @@ extern Oid index_create(Relation heapRelation,
bool allow_system_table_mods, bool allow_system_table_mods,
bool skip_build, bool skip_build,
bool concurrent, bool concurrent,
bool is_internal); bool is_internal,
bool if_not_exists);
extern void index_constraint_create(Relation heapRelation, extern void index_constraint_create(Relation heapRelation,
Oid indexRelationId, Oid indexRelationId,

View File

@ -2256,6 +2256,7 @@ typedef struct IndexStmt
bool deferrable; /* is the constraint DEFERRABLE? */ bool deferrable; /* is the constraint DEFERRABLE? */
bool initdeferred; /* is the constraint INITIALLY DEFERRED? */ bool initdeferred; /* is the constraint INITIALLY DEFERRED? */
bool concurrent; /* should this be a concurrent index build? */ bool concurrent; /* should this be a concurrent index build? */
bool if_not_exists; /* just do nothing if index already exists? */
} IndexStmt; } IndexStmt;
/* ---------------------- /* ----------------------

View File

@ -6,6 +6,12 @@
-- BTREE -- BTREE
-- --
CREATE INDEX onek_unique1 ON onek USING btree(unique1 int4_ops); CREATE INDEX onek_unique1 ON onek USING btree(unique1 int4_ops);
CREATE INDEX IF NOT EXISTS onek_unique1 ON onek USING btree(unique1 int4_ops);
NOTICE: relation "onek_unique1" already exists, skipping
CREATE INDEX IF NOT EXISTS ON onek USING btree(unique1 int4_ops);
ERROR: syntax error at or near "ON"
LINE 1: CREATE INDEX IF NOT EXISTS ON onek USING btree(unique1 int4_...
^
CREATE INDEX onek_unique2 ON onek USING btree(unique2 int4_ops); CREATE INDEX onek_unique2 ON onek USING btree(unique2 int4_ops);
CREATE INDEX onek_hundred ON onek USING btree(hundred int4_ops); CREATE INDEX onek_hundred ON onek USING btree(hundred int4_ops);
CREATE INDEX onek_stringu1 ON onek USING btree(stringu1 name_ops); 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;
CREATE TABLE concur_heap (f1 text, f2 text); CREATE TABLE concur_heap (f1 text, f2 text);
-- empty table -- empty table
CREATE INDEX CONCURRENTLY concur_index1 ON concur_heap(f2,f1); CREATE INDEX CONCURRENTLY concur_index1 ON concur_heap(f2,f1);
CREATE INDEX CONCURRENTLY IF NOT EXISTS concur_index1 ON concur_heap(f2,f1);
NOTICE: relation "concur_index1" already exists, skipping
INSERT INTO concur_heap VALUES ('a','b'); INSERT INTO concur_heap VALUES ('a','b');
INSERT INTO concur_heap VALUES ('b','b'); INSERT INTO concur_heap VALUES ('b','b');
-- unique index -- unique index
CREATE UNIQUE INDEX CONCURRENTLY concur_index2 ON concur_heap(f1); CREATE UNIQUE INDEX CONCURRENTLY concur_index2 ON concur_heap(f1);
CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS concur_index2 ON concur_heap(f1);
NOTICE: relation "concur_index2" already exists, skipping
-- check if constraint is set up properly to be enforced -- check if constraint is set up properly to be enforced
INSERT INTO concur_heap VALUES ('b','x'); INSERT INTO concur_heap VALUES ('b','x');
ERROR: duplicate key value violates unique constraint "concur_index2" ERROR: duplicate key value violates unique constraint "concur_index2"

View File

@ -8,6 +8,10 @@
-- --
CREATE INDEX onek_unique1 ON onek USING btree(unique1 int4_ops); CREATE INDEX onek_unique1 ON onek USING btree(unique1 int4_ops);
CREATE INDEX IF NOT EXISTS onek_unique1 ON onek USING btree(unique1 int4_ops);
CREATE INDEX IF NOT EXISTS ON onek USING btree(unique1 int4_ops);
CREATE INDEX onek_unique2 ON onek USING btree(unique2 int4_ops); CREATE INDEX onek_unique2 ON onek USING btree(unique2 int4_ops);
CREATE INDEX onek_hundred ON onek USING btree(hundred int4_ops); 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;
CREATE TABLE concur_heap (f1 text, f2 text); CREATE TABLE concur_heap (f1 text, f2 text);
-- empty table -- empty table
CREATE INDEX CONCURRENTLY concur_index1 ON concur_heap(f2,f1); CREATE INDEX CONCURRENTLY concur_index1 ON concur_heap(f2,f1);
CREATE INDEX CONCURRENTLY IF NOT EXISTS concur_index1 ON concur_heap(f2,f1);
INSERT INTO concur_heap VALUES ('a','b'); INSERT INTO concur_heap VALUES ('a','b');
INSERT INTO concur_heap VALUES ('b','b'); INSERT INTO concur_heap VALUES ('b','b');
-- unique index -- unique index
CREATE UNIQUE INDEX CONCURRENTLY concur_index2 ON concur_heap(f1); CREATE UNIQUE INDEX CONCURRENTLY concur_index2 ON concur_heap(f1);
CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS concur_index2 ON concur_heap(f1);
-- check if constraint is set up properly to be enforced -- check if constraint is set up properly to be enforced
INSERT INTO concur_heap VALUES ('b','x'); INSERT INTO concur_heap VALUES ('b','x');
-- check if constraint is enforced properly at build time -- check if constraint is enforced properly at build time