]> granicus.if.org Git - postgresql/commitdiff
Implement IF NOT EXIST for CREATE INDEX.
authorFujii Masao <fujii@postgresql.org>
Thu, 6 Nov 2014 09:48:33 +0000 (18:48 +0900)
committerFujii Masao <fujii@postgresql.org>
Thu, 6 Nov 2014 09:48:33 +0000 (18:48 +0900)
Fabrízio de Royes Mello, reviewed by Marti Raudsepp, Adam Brightwell and me.

doc/src/sgml/ref/create_index.sgml
src/backend/catalog/index.c
src/backend/catalog/toasting.c
src/backend/commands/indexcmds.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/include/catalog/index.h
src/include/nodes/parsenodes.h
src/test/regress/expected/create_index.out
src/test/regress/sql/create_index.sql

index 43df32f977a104eb5a5f6ecdc19ba606f64e79da..ead33750fa246e3274d9ba7a4db640d2aa1c9eed 100644 (file)
@@ -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>
index 01ed880b1c71cf4f6d585327f791aa91db2b691d..0c31aa95d70a169bb83f3ce7db735f46eee53e03 100644 (file)
@@ -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
index 160f006ecdf1e3c3578abf6bc122b47d4a0fea70..5ef6dccb91e053b3061e4ef94914e84b2ccafd62 100644 (file)
@@ -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);
 
index 3c1e90eb0e9f40a4122c6f5d6c7367660a04a337..02055950b58b523f14c87652ad0a7d5518000f38 100644 (file)
@@ -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)
index 21b070acdaf93eb446d0b0a6e2bc390f99a2ba22..7b51d331777e6d51a840ea5e7f118925828843ac 100644 (file)
@@ -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;
 }
index 358395f61f4a2ed903ccf31680fae514d8993afa..d5db71d3a86061d93b4beb598d5a916f3a74afb4 100644 (file)
@@ -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;
 }
index 0de9584e5315f312e81413897eaaeb3d5f987ea7..bd180e7e87ba941b30a02ddbbc5017533c7584b5 100644 (file)
@@ -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;
                                }
                ;
index 006b1801a3217cc34e283b4fc3cff2b8443f839c..098ac7df19956eb9c18abd7960ee74eabe04e395 100644 (file)
@@ -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,
index cef95446984c4ac0e574dd520803120ea3da8c4c..3e4f815852d5659a6d0e2bae77e4a8b4a98c6213 100644 (file)
@@ -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;
 
 /* ----------------------
index d903c4bc26c76ff527b74e4835465be56b3c0218..26d883c447eb0326bdd5ba992b4ab69bbfc09527 100644 (file)
@@ -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"
index 989fc97eee7c8e9b06e494de819098f8673ebeff..e08f35ebcf13ddd570763d6478cab0aa70b49db3 100644 (file)
@@ -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