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:
@ -21,7 +21,7 @@ PostgreSQL documentation
|
||||
|
||||
<refsynopsisdiv>
|
||||
<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 } ] [, ...] )
|
||||
[ WITH ( <replaceable class="PARAMETER">storage_parameter</replaceable> = <replaceable class="PARAMETER">value</replaceable> [, ... ] ) ]
|
||||
[ TABLESPACE <replaceable class="parameter">tablespace_name</replaceable> ]
|
||||
@ -126,6 +126,18 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ <replaceable class="parameter">name</
|
||||
</listitem>
|
||||
</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>
|
||||
<term><replaceable class="parameter">name</replaceable></term>
|
||||
<listitem>
|
||||
|
@ -674,6 +674,8 @@ UpdateIndexRelation(Oid indexoid,
|
||||
* will be marked "invalid" and the caller must take additional steps
|
||||
* to fix it up.
|
||||
* 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.
|
||||
*/
|
||||
@ -697,7 +699,8 @@ index_create(Relation heapRelation,
|
||||
bool allow_system_table_mods,
|
||||
bool skip_build,
|
||||
bool concurrent,
|
||||
bool is_internal)
|
||||
bool is_internal,
|
||||
bool if_not_exists)
|
||||
{
|
||||
Oid heapRelationId = RelationGetRelid(heapRelation);
|
||||
Relation pg_class;
|
||||
@ -773,10 +776,22 @@ index_create(Relation heapRelation,
|
||||
elog(ERROR, "shared relations must be placed in pg_global tablespace");
|
||||
|
||||
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,
|
||||
(errcode(ERRCODE_DUPLICATE_TABLE),
|
||||
errmsg("relation \"%s\" already exists",
|
||||
indexRelationName)));
|
||||
}
|
||||
|
||||
/*
|
||||
* construct tuple descriptor for index tuples
|
||||
|
@ -342,7 +342,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
|
||||
rel->rd_rel->reltablespace,
|
||||
collationObjectId, classObjectId, coloptions, (Datum) 0,
|
||||
true, false, false, false,
|
||||
true, false, false, true);
|
||||
true, false, false, true, false);
|
||||
|
||||
heap_close(toast_rel, NoLock);
|
||||
|
||||
|
@ -610,7 +610,14 @@ DefineIndex(Oid relationId,
|
||||
stmt->isconstraint, stmt->deferrable, stmt->initdeferred,
|
||||
allowSystemTableMods,
|
||||
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 */
|
||||
if (stmt->idxcomment != NULL)
|
||||
|
@ -2907,6 +2907,7 @@ _copyIndexStmt(const IndexStmt *from)
|
||||
COPY_SCALAR_FIELD(deferrable);
|
||||
COPY_SCALAR_FIELD(initdeferred);
|
||||
COPY_SCALAR_FIELD(concurrent);
|
||||
COPY_SCALAR_FIELD(if_not_exists);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
@ -1210,6 +1210,7 @@ _equalIndexStmt(const IndexStmt *a, const IndexStmt *b)
|
||||
COMPARE_SCALAR_FIELD(deferrable);
|
||||
COMPARE_SCALAR_FIELD(initdeferred);
|
||||
COMPARE_SCALAR_FIELD(concurrent);
|
||||
COMPARE_SCALAR_FIELD(if_not_exists);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -6434,6 +6434,32 @@ IndexStmt: CREATE opt_unique INDEX opt_concurrently opt_index_name
|
||||
n->isconstraint = false;
|
||||
n->deferrable = 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;
|
||||
}
|
||||
;
|
||||
|
@ -60,7 +60,8 @@ extern Oid index_create(Relation heapRelation,
|
||||
bool allow_system_table_mods,
|
||||
bool skip_build,
|
||||
bool concurrent,
|
||||
bool is_internal);
|
||||
bool is_internal,
|
||||
bool if_not_exists);
|
||||
|
||||
extern void index_constraint_create(Relation heapRelation,
|
||||
Oid indexRelationId,
|
||||
|
@ -2256,6 +2256,7 @@ typedef struct IndexStmt
|
||||
bool deferrable; /* is the constraint DEFERRABLE? */
|
||||
bool initdeferred; /* is the constraint INITIALLY DEFERRED? */
|
||||
bool concurrent; /* should this be a concurrent index build? */
|
||||
bool if_not_exists; /* just do nothing if index already exists? */
|
||||
} IndexStmt;
|
||||
|
||||
/* ----------------------
|
||||
|
@ -6,6 +6,12 @@
|
||||
-- BTREE
|
||||
--
|
||||
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_hundred ON onek USING btree(hundred int4_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);
|
||||
-- empty table
|
||||
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 ('b','b');
|
||||
-- unique index
|
||||
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
|
||||
INSERT INTO concur_heap VALUES ('b','x');
|
||||
ERROR: duplicate key value violates unique constraint "concur_index2"
|
||||
|
@ -8,6 +8,10 @@
|
||||
--
|
||||
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_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);
|
||||
-- empty table
|
||||
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 ('b','b');
|
||||
-- unique index
|
||||
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
|
||||
INSERT INTO concur_heap VALUES ('b','x');
|
||||
-- check if constraint is enforced properly at build time
|
||||
|
Reference in New Issue
Block a user