From: Fujii Masao Date: Thu, 6 Nov 2014 09:48:33 +0000 (+0900) Subject: Implement IF NOT EXIST for CREATE INDEX. X-Git-Tag: REL9_5_ALPHA1~1262 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=08309aaf74ee879699165ec8a2d53e56f2d2e947;p=postgresql Implement IF NOT EXIST for CREATE INDEX. Fabrízio de Royes Mello, reviewed by Marti Raudsepp, Adam Brightwell and me. --- diff --git a/doc/src/sgml/ref/create_index.sgml b/doc/src/sgml/ref/create_index.sgml index 43df32f977..ead33750fa 100644 --- a/doc/src/sgml/ref/create_index.sgml +++ b/doc/src/sgml/ref/create_index.sgml @@ -21,7 +21,7 @@ PostgreSQL documentation -CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ name ] ON table_name [ USING method ] +CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON table_name [ USING method ] ( { column_name | ( expression ) } [ COLLATE collation ] [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] ) [ WITH ( storage_parameter = value [, ... ] ) ] [ TABLESPACE tablespace_name ] @@ -126,6 +126,18 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ name + + IF NOT EXISTS + + + 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 IF NOT EXISTS is specified. + + + + name diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 01ed880b1c..0c31aa95d7 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -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 diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index 160f006ecd..5ef6dccb91 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -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); diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 3c1e90eb0e..02055950b5 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -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) diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 21b070acda..7b51d33177 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -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; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 358395f61f..d5db71d3a8 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -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; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 0de9584e53..bd180e7e87 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -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; } ; diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index 006b1801a3..098ac7df19 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -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, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index cef9544698..3e4f815852 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -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; /* ---------------------- diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index d903c4bc26..26d883c447 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -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" diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index 989fc97eee..e08f35ebcf 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -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