Add CREATE COLLATION IF NOT EXISTS clause
authorPeter Eisentraut <peter_e@gmx.net>
Thu, 9 Feb 2017 03:51:09 +0000 (22:51 -0500)
committerPeter Eisentraut <peter_e@gmx.net>
Wed, 15 Feb 2017 15:01:28 +0000 (10:01 -0500)
The core of the functionality was already implemented when
pg_import_system_collations was added.  This just exposes it as an
option in the SQL command.

doc/src/sgml/ref/create_collation.sgml
src/backend/commands/collationcmds.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/backend/tcop/utility.c
src/include/commands/collationcmds.h
src/include/nodes/parsenodes.h
src/test/regress/expected/collate.linux.utf8.out
src/test/regress/sql/collate.linux.utf8.sql

index d757cdfb4348b2007c4cab76c19a6cbe8a11bbf5..c09e5bd6d4079b6d4c8961bb6a207426a6e3b52d 100644 (file)
 
  <refsynopsisdiv>
 <synopsis>
-CREATE COLLATION <replaceable>name</replaceable> (
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> (
     [ LOCALE = <replaceable>locale</replaceable>, ]
     [ LC_COLLATE = <replaceable>lc_collate</replaceable>, ]
     [ LC_CTYPE = <replaceable>lc_ctype</replaceable> ]
 )
-CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
+CREATE COLLATION [ IF NOT EXISTS ] <replaceable>name</replaceable> FROM <replaceable>existing_collation</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -47,6 +47,17 @@ CREATE COLLATION <replaceable>name</replaceable> FROM <replaceable>existing_coll
   <title>Parameters</title>
 
    <variablelist>
+    <varlistentry>
+     <term><literal>IF NOT EXISTS</literal></term>
+     <listitem>
+      <para>
+       Do not throw an error if a collation with the same name already exists.
+       A notice is issued in this case. Note that there is no guarantee that
+       the existing collation is anything like the one that would have been created.
+      </para>
+     </listitem>
+    </varlistentry>
+
     <varlistentry>
      <term><replaceable>name</replaceable></term>
 
index e165d4b2a6b2c57c09256416a5674c2ece6031b3..919cfc6a0679ac80418aea5ce871278dc09b3c94 100644 (file)
@@ -37,7 +37,7 @@
  * CREATE COLLATION
  */
 ObjectAddress
-DefineCollation(ParseState *pstate, List *names, List *parameters)
+DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_exists)
 {
    char       *collName;
    Oid         collNamespace;
@@ -137,7 +137,7 @@ DefineCollation(ParseState *pstate, List *names, List *parameters)
                             GetDatabaseEncoding(),
                             collcollate,
                             collctype,
-                            false);
+                            if_not_exists);
 
    if (!OidIsValid(newoid))
        return InvalidObjectAddress;
index 12324ab63f13814ef7d4b5b2a1d41c60c483919a..05d8538717a53759a5731795e86439650fa4e5c7 100644 (file)
@@ -3105,6 +3105,7 @@ _copyDefineStmt(const DefineStmt *from)
    COPY_NODE_FIELD(defnames);
    COPY_NODE_FIELD(args);
    COPY_NODE_FIELD(definition);
+   COPY_SCALAR_FIELD(if_not_exists);
 
    return newnode;
 }
index 6d1dabe17e9602635b168c8d266a76adfc7d901b..d595cd74812e2f60e9b3d7805ef3fa152254a5a0 100644 (file)
@@ -1211,6 +1211,7 @@ _equalDefineStmt(const DefineStmt *a, const DefineStmt *b)
    COMPARE_NODE_FIELD(defnames);
    COMPARE_NODE_FIELD(args);
    COMPARE_NODE_FIELD(definition);
+   COMPARE_SCALAR_FIELD(if_not_exists);
 
    return true;
 }
index 174773bdf3173802c86a49773e1d28cdb5f3d7dc..5cb82977d5dec5314f81db646a9f2987e304904a 100644 (file)
@@ -5610,6 +5610,16 @@ DefineStmt:
                    n->definition = $4;
                    $$ = (Node *)n;
                }
+           | CREATE COLLATION IF_P NOT EXISTS any_name definition
+               {
+                   DefineStmt *n = makeNode(DefineStmt);
+                   n->kind = OBJECT_COLLATION;
+                   n->args = NIL;
+                   n->defnames = $6;
+                   n->definition = $7;
+                   n->if_not_exists = true;
+                   $$ = (Node *)n;
+               }
            | CREATE COLLATION any_name FROM any_name
                {
                    DefineStmt *n = makeNode(DefineStmt);
@@ -5619,6 +5629,16 @@ DefineStmt:
                    n->definition = list_make1(makeDefElem("from", (Node *) $5, @5));
                    $$ = (Node *)n;
                }
+           | CREATE COLLATION IF_P NOT EXISTS any_name FROM any_name
+               {
+                   DefineStmt *n = makeNode(DefineStmt);
+                   n->kind = OBJECT_COLLATION;
+                   n->args = NIL;
+                   n->defnames = $6;
+                   n->definition = list_make1(makeDefElem("from", (Node *) $8, @8));
+                   n->if_not_exists = true;
+                   $$ = (Node *)n;
+               }
        ;
 
 definition: '(' def_list ')'                       { $$ = $2; }
index 5d3be38bf501faae54f3daec3706ff58e29357f3..3bc0ae5e7e6aad8fbafbce1f9354ca14995b7638 100644 (file)
@@ -1271,7 +1271,8 @@ ProcessUtilitySlow(ParseState *pstate,
                            Assert(stmt->args == NIL);
                            address = DefineCollation(pstate,
                                                      stmt->defnames,
-                                                     stmt->definition);
+                                                     stmt->definition,
+                                                     stmt->if_not_exists);
                            break;
                        default:
                            elog(ERROR, "unrecognized define stmt type: %d",
index 699ce2f9ee362c039144dad544e67e868decdc87..3b2fcb8271139f1b8c8ffe51ab66e1a999d76ff3 100644 (file)
@@ -18,7 +18,7 @@
 #include "catalog/objectaddress.h"
 #include "nodes/parsenodes.h"
 
-extern ObjectAddress DefineCollation(ParseState *pstate, List *names, List *parameters);
+extern ObjectAddress DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_exists);
 extern void IsThereCollationInNamespace(const char *collname, Oid nspOid);
 
 #endif   /* COLLATIONCMDS_H */
index 07a84361432aa2f84d6dc690a7c9b0f8f53d2540..5afc3ebea04489ed58af9f5046a27f5e6f072ef2 100644 (file)
@@ -2380,6 +2380,7 @@ typedef struct DefineStmt
    List       *defnames;       /* qualified name (list of Value strings) */
    List       *args;           /* a list of TypeName (if needed) */
    List       *definition;     /* a list of DefElem */
+   bool        if_not_exists;  /* just do nothing if it already exists? */
 } DefineStmt;
 
 /* ----------------------
index 286c972fbba12292294d327ebeb00c864c94def3..293e78641ecc6bc23520a27125df70b6e1d41f77 100644 (file)
@@ -963,6 +963,10 @@ END
 $$;
 CREATE COLLATION test0 FROM "C"; -- fail, duplicate name
 ERROR:  collation "test0" for encoding "UTF8" already exists
+CREATE COLLATION IF NOT EXISTS test0 FROM "C"; -- ok, skipped
+NOTICE:  collation "test0" for encoding "UTF8" already exists, skipping
+CREATE COLLATION IF NOT EXISTS test0 (locale = 'foo'); -- ok, skipped
+NOTICE:  collation "test0" for encoding "UTF8" already exists, skipping
 do $$
 BEGIN
   EXECUTE 'CREATE COLLATION test1 (lc_collate = ' ||
index 3b7cc6cf2bcc086016cb3ae2b04ad8e8915e9bb2..c349cbde2b90ab6723eb7ba9d63c683be4f6b065 100644 (file)
@@ -325,6 +325,8 @@ BEGIN
 END
 $$;
 CREATE COLLATION test0 FROM "C"; -- fail, duplicate name
+CREATE COLLATION IF NOT EXISTS test0 FROM "C"; -- ok, skipped
+CREATE COLLATION IF NOT EXISTS test0 (locale = 'foo'); -- ok, skipped
 do $$
 BEGIN
   EXECUTE 'CREATE COLLATION test1 (lc_collate = ' ||