Commit 08309aaf authored by Fujii Masao's avatar Fujii Masao

Implement IF NOT EXIST for CREATE INDEX.

Fabrízio de Royes Mello, reviewed by Marti Raudsepp, Adam Brightwell and me.
parent 171c377a
...@@ -21,7 +21,7 @@ PostgreSQL documentation ...@@ -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</ ...@@ -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>
......
...@@ -674,6 +674,8 @@ UpdateIndexRelation(Oid indexoid, ...@@ -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, ...@@ -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, ...@@ -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
......
...@@ -342,7 +342,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, ...@@ -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);
......
...@@ -610,7 +610,14 @@ DefineIndex(Oid relationId, ...@@ -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)
......
...@@ -2907,6 +2907,7 @@ _copyIndexStmt(const IndexStmt *from) ...@@ -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;
} }
......
...@@ -1210,6 +1210,7 @@ _equalIndexStmt(const IndexStmt *a, const IndexStmt *b) ...@@ -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;
} }
......
...@@ -6434,6 +6434,32 @@ IndexStmt: CREATE opt_unique INDEX opt_concurrently opt_index_name ...@@ -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;
} }
; ;
......
...@@ -60,7 +60,8 @@ extern Oid index_create(Relation heapRelation, ...@@ -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,
......
...@@ -2256,6 +2256,7 @@ typedef struct IndexStmt ...@@ -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;
/* ---------------------- /* ----------------------
......
...@@ -6,6 +6,12 @@ ...@@ -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; ...@@ -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"
......
...@@ -8,6 +8,10 @@ ...@@ -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; ...@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment