]> granicus.if.org Git - postgresql/commitdiff
Add IF NOT EXISTS for CREATE SERVER and CREATE USER MAPPING
authorAndrew Dunstan <andrew@dunslane.net>
Mon, 20 Mar 2017 20:40:45 +0000 (16:40 -0400)
committerAndrew Dunstan <andrew@dunslane.net>
Mon, 20 Mar 2017 20:40:45 +0000 (16:40 -0400)
There is still some inconsistency with the error messages surrounding
foreign servers. Some use the word "foreign" and some don't. My
inclination is to remove all such uses of "foreign" on the basis that
the  CREATE/ALTER/DROP SERVER commands don't use the word. However, that
is left for another day. In this patch I have kept to the existing usage
in the affected commands, which omits "foreign".

Anastasia Lubennikova, reviewed by Arthur Zakirov and Ashtosh Bapat.

Discussion: http://postgr.es/m/7c2ab9b8-388a-1ce0-23a3-7acf2a0ed3c6@postgrespro.ru

doc/src/sgml/ref/create_server.sgml
doc/src/sgml/ref/create_user_mapping.sgml
src/backend/commands/foreigncmds.c
src/backend/parser/gram.y
src/include/nodes/parsenodes.h
src/test/regress/expected/foreign_data.out
src/test/regress/sql/foreign_data.sql

index 734c6c9fe81aa36d079e089521967ddbc119b2c8..7318481487f2e7f0634f08bb064e4c8814908791 100644 (file)
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE SERVER <replaceable class="parameter">server_name</replaceable> [ TYPE '<replaceable class="parameter">server_type</replaceable>' ] [ VERSION '<replaceable class="parameter">server_version</replaceable>' ]
+CREATE SERVER [IF NOT EXISTS] <replaceable class="parameter">server_name</replaceable> [ TYPE '<replaceable class="parameter">server_type</replaceable>' ] [ VERSION '<replaceable class="parameter">server_version</replaceable>' ]
     FOREIGN DATA WRAPPER <replaceable class="parameter">fdw_name</replaceable>
     [ OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [, ... ] ) ]
 </synopsis>
@@ -56,6 +56,18 @@ CREATE SERVER <replaceable class="parameter">server_name</replaceable> [ TYPE '<
   <title>Parameters</title>
 
   <variablelist>
+  <varlistentry>
+    <term><literal>IF NOT EXISTS</></term>
+    <listitem>
+     <para>
+      Do not throw an error if a server with the same name already exists.
+      A notice is issued in this case.  Note that there is no guarantee that
+      the existing server is anything like the one that would have been
+      created.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><replaceable class="parameter">server_name</replaceable></term>
     <listitem>
index 44fe302fb5c49f097f546991676fced3cfae1bac..1c44679a985ce5246cfa0bab7f3489e9d023790e 100644 (file)
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE USER MAPPING FOR { <replaceable class="parameter">user_name</replaceable> | USER | CURRENT_USER | PUBLIC }
+CREATE USER MAPPING [IF NOT EXISTS] FOR { <replaceable class="parameter">user_name</replaceable> | USER | CURRENT_USER | PUBLIC }
     SERVER <replaceable class="parameter">server_name</replaceable>
     [ OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [ , ... ] ) ]
 </synopsis>
@@ -50,6 +50,18 @@ CREATE USER MAPPING FOR { <replaceable class="parameter">user_name</replaceable>
   <title>Parameters</title>
 
   <variablelist>
+  <varlistentry>
+    <term><literal>IF NOT EXISTS</></term>
+    <listitem>
+     <para>
+      Do not throw an error if a mapping of the given user to the given foreign
+      server already exists. A notice is issued in this case.  Note that there
+      is no guarantee that the existing user mapping is anything like the one
+      that would have been created.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><replaceable class="parameter">user_name</replaceable></term>
     <listitem>
index 7f551149d2db474ca1e2841aaba4f28cd7643e85..68100df0830abf62d69197a2b6b081c3fcb7718a 100644 (file)
@@ -879,12 +879,25 @@ CreateForeignServer(CreateForeignServerStmt *stmt)
 
        /*
         * Check that there is no other foreign server by this name.
+        * Do nothing if IF NOT EXISTS was enforced.
         */
        if (GetForeignServerByName(stmt->servername, true) != NULL)
-               ereport(ERROR,
-                               (errcode(ERRCODE_DUPLICATE_OBJECT),
-                                errmsg("server \"%s\" already exists",
-                                               stmt->servername)));
+       {
+               if (stmt->if_not_exists)
+               {
+                       ereport(NOTICE,
+                                       (errcode(ERRCODE_DUPLICATE_OBJECT),
+                                        errmsg("server \"%s\" already exists, skipping",
+                                                       stmt->servername)));
+                       heap_close(rel, RowExclusiveLock);
+                       return InvalidObjectAddress;
+               }
+               else
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_DUPLICATE_OBJECT),
+                                        errmsg("server \"%s\" already exists",
+                                                       stmt->servername)));
+       }
 
        /*
         * Check that the FDW exists and that we have USAGE on it. Also get the
@@ -1152,12 +1165,27 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
        umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
                                                   ObjectIdGetDatum(useId),
                                                   ObjectIdGetDatum(srv->serverid));
+
        if (OidIsValid(umId))
-               ereport(ERROR,
+       {
+               if (stmt->if_not_exists)
+               {
+                       ereport(NOTICE,
+                               (errcode(ERRCODE_DUPLICATE_OBJECT),
+                                errmsg("user mapping for \"%s\" already exists for server %s, skipping",
+                                               MappingUserName(useId),
+                                               stmt->servername)));
+
+                       heap_close(rel, RowExclusiveLock);
+                       return InvalidObjectAddress;
+               }
+               else
+                       ereport(ERROR,
                                (errcode(ERRCODE_DUPLICATE_OBJECT),
                                 errmsg("user mapping for \"%s\" already exists for server %s",
                                                MappingUserName(useId),
                                                stmt->servername)));
+       }
 
        fdw = GetForeignDataWrapper(srv->fdwid);
 
index 6316688a8835c898db4e4bda23b7cf53255544cd..d0d45a557b425890e711d9b3039d40e942989429 100644 (file)
@@ -4621,6 +4621,19 @@ CreateForeignServerStmt: CREATE SERVER name opt_type opt_foreign_server_version
                                        n->version = $5;
                                        n->fdwname = $9;
                                        n->options = $10;
+                                       n->if_not_exists = false;
+                                       $$ = (Node *) n;
+                               }
+                               | CREATE SERVER IF_P NOT EXISTS name opt_type opt_foreign_server_version
+                                                FOREIGN DATA_P WRAPPER name create_generic_options
+                               {
+                                       CreateForeignServerStmt *n = makeNode(CreateForeignServerStmt);
+                                       n->servername = $6;
+                                       n->servertype = $7;
+                                       n->version = $8;
+                                       n->fdwname = $12;
+                                       n->options = $13;
+                                       n->if_not_exists = true;
                                        $$ = (Node *) n;
                                }
                ;
@@ -4853,6 +4866,16 @@ CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_gen
                                        n->user = $5;
                                        n->servername = $7;
                                        n->options = $8;
+                                       n->if_not_exists = false;
+                                       $$ = (Node *) n;
+                               }
+                               | CREATE USER MAPPING IF_P NOT EXISTS FOR auth_ident SERVER name create_generic_options
+                               {
+                                       CreateUserMappingStmt *n = makeNode(CreateUserMappingStmt);
+                                       n->user = $8;
+                                       n->servername = $10;
+                                       n->options = $11;
+                                       n->if_not_exists = true;
                                        $$ = (Node *) n;
                                }
                ;
index d576523f6a82676b7bd71ca1ce0c593167ed8211..a15df229a494696f9663af0b5defccba25d4ce83 100644 (file)
@@ -2154,6 +2154,7 @@ typedef struct CreateForeignServerStmt
        char       *servertype;         /* optional server type */
        char       *version;            /* optional server version */
        char       *fdwname;            /* FDW name */
+       bool            if_not_exists;  /* just do nothing if it already exists? */
        List       *options;            /* generic options to server */
 } CreateForeignServerStmt;
 
@@ -2188,6 +2189,7 @@ typedef struct CreateUserMappingStmt
        NodeTag         type;
        RoleSpec   *user;                       /* user role */
        char       *servername;         /* server name */
+       bool            if_not_exists;  /* just do nothing if it already exists? */
        List       *options;            /* generic options to server */
 } CreateUserMappingStmt;
 
index 328366bcfc7b871419bf3b61aa4c93c6e46332c7..1c7a7593f9e3b372627281ec34199fb1bb40e1d2 100644 (file)
@@ -221,6 +221,10 @@ CREATE FOREIGN DATA WRAPPER foo;
 CREATE SERVER s1 FOREIGN DATA WRAPPER foo;
 COMMENT ON SERVER s1 IS 'foreign server';
 CREATE USER MAPPING FOR current_user SERVER s1;
+CREATE USER MAPPING FOR current_user SERVER s1;                                -- ERROR
+ERROR:  user mapping for "regress_foreign_data_user" already exists for server s1
+CREATE USER MAPPING IF NOT EXISTS FOR current_user SERVER s1; -- NOTICE
+NOTICE:  user mapping for "regress_foreign_data_user" already exists for server s1, skipping
 \dew+
                                                 List of foreign-data wrappers
     Name    |           Owner           | Handler |        Validator         | Access privileges | FDW Options | Description 
@@ -284,6 +288,8 @@ CREATE FOREIGN DATA WRAPPER foo OPTIONS ("test wrapper" 'true');
 CREATE SERVER s1 FOREIGN DATA WRAPPER foo;
 CREATE SERVER s1 FOREIGN DATA WRAPPER foo;                  -- ERROR
 ERROR:  server "s1" already exists
+CREATE SERVER IF NOT EXISTS s1 FOREIGN DATA WRAPPER foo;       -- No ERROR, just NOTICE
+NOTICE:  server "s1" already exists, skipping
 CREATE SERVER s2 FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b');
 CREATE SERVER s3 TYPE 'oracle' FOREIGN DATA WRAPPER foo;
 CREATE SERVER s4 TYPE 'oracle' FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b');
index c13d5ffbe92758619f4b71a0813aef805deed1b1..aaf079cf525767cdeda1230cbb2104fa9af689ed 100644 (file)
@@ -104,6 +104,8 @@ CREATE FOREIGN DATA WRAPPER foo;
 CREATE SERVER s1 FOREIGN DATA WRAPPER foo;
 COMMENT ON SERVER s1 IS 'foreign server';
 CREATE USER MAPPING FOR current_user SERVER s1;
+CREATE USER MAPPING FOR current_user SERVER s1;                                -- ERROR
+CREATE USER MAPPING IF NOT EXISTS FOR current_user SERVER s1; -- NOTICE
 \dew+
 \des+
 \deu+
@@ -121,6 +123,7 @@ CREATE SERVER s1 FOREIGN DATA WRAPPER foo;                  -- ERROR
 CREATE FOREIGN DATA WRAPPER foo OPTIONS ("test wrapper" 'true');
 CREATE SERVER s1 FOREIGN DATA WRAPPER foo;
 CREATE SERVER s1 FOREIGN DATA WRAPPER foo;                  -- ERROR
+CREATE SERVER IF NOT EXISTS s1 FOREIGN DATA WRAPPER foo;       -- No ERROR, just NOTICE
 CREATE SERVER s2 FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b');
 CREATE SERVER s3 TYPE 'oracle' FOREIGN DATA WRAPPER foo;
 CREATE SERVER s4 TYPE 'oracle' FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b');