]> granicus.if.org Git - postgresql/commitdiff
Add CINE option for CREATE TABLE AS and CREATE MATERIALIZED VIEW
authorAndrew Dunstan <andrew@dunslane.net>
Sat, 13 Dec 2014 18:56:09 +0000 (13:56 -0500)
committerAndrew Dunstan <andrew@dunslane.net>
Sat, 13 Dec 2014 18:56:09 +0000 (13:56 -0500)
Fabrízio de Royes Mello reviewed by Rushabh Lathia.

doc/src/sgml/ref/create_materialized_view.sgml
doc/src/sgml/ref/create_table_as.sgml
src/backend/commands/createas.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/include/nodes/parsenodes.h
src/test/regress/expected/create_table.out
src/test/regress/expected/matview.out
src/test/regress/sql/create_table.sql
src/test/regress/sql/matview.sql

index 2c73852ae389412c9dd0a1f3632f93ae3b18c1e9..8a0fb4d3ca3789faa8c47145973b068d1624734d 100644 (file)
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE MATERIALIZED VIEW <replaceable>table_name</replaceable>
+CREATE MATERIALIZED VIEW [ IF NOT EXISTS ] <replaceable>table_name</replaceable>
     [ (<replaceable>column_name</replaceable> [, ...] ) ]
     [ WITH ( <replaceable class="PARAMETER">storage_parameter</replaceable> [= <replaceable class="PARAMETER">value</replaceable>] [, ... ] ) ]
     [ TABLESPACE <replaceable class="PARAMETER">tablespace_name</replaceable> ]
@@ -53,6 +53,18 @@ CREATE MATERIALIZED VIEW <replaceable>table_name</replaceable>
  <refsect1>
   <title>Parameters</title>
 
+   <varlistentry>
+    <term><literal>IF NOT EXISTS</></term>
+    <listitem>
+     <para>
+      Do not throw an error if a materialized view with the same name already
+      exists. A notice is issued in this case.  Note that there is no guarantee
+      that the existing materialized view is anything like the one that would
+      have been created.
+     </para>
+    </listitem>
+   </varlistentry>
+
   <variablelist>
    <varlistentry>
     <term><replaceable>table_name</replaceable></term>
index 60300ff21e9d3fe027aa2b15012390b5ea5096bc..8e4ada794d49947bc0f1e1ac35ea5acba8196570 100644 (file)
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE <replaceable>table_name</replaceable>
+CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] <replaceable>table_name</replaceable>
     [ (<replaceable>column_name</replaceable> [, ...] ) ]
     [ WITH ( <replaceable class="PARAMETER">storage_parameter</replaceable> [= <replaceable class="PARAMETER">value</replaceable>] [, ... ] ) | WITH OIDS | WITHOUT OIDS ]
     [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
@@ -90,6 +90,17 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE <replaceable
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term><literal>IF NOT EXISTS</></term>
+    <listitem>
+     <para>
+      Do not throw an error if a relation with the same name already exists.
+      A notice is issued in this case. Refer to <xref linkend="sql-createtable">
+      for details.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term><replaceable>table_name</replaceable></term>
     <listitem>
index 5e0ac585603171ed2d7e846c61a23152c581463c..72315c2f3fc5dd7bd218949036e67703148feee7 100644 (file)
@@ -28,6 +28,7 @@
 #include "access/sysattr.h"
 #include "access/xact.h"
 #include "access/xlog.h"
+#include "catalog/namespace.h"
 #include "catalog/toasting.h"
 #include "commands/createas.h"
 #include "commands/matview.h"
@@ -86,6 +87,22 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString,
        QueryDesc  *queryDesc;
        ScanDirection dir;
 
+       if (stmt->if_not_exists)
+       {
+               Oid     nspid;
+
+               nspid = RangeVarGetCreationNamespace(stmt->into->rel);
+
+               if (get_relname_relid(stmt->into->rel->relname, nspid))
+               {
+                       ereport(NOTICE,
+                                       (errcode(ERRCODE_DUPLICATE_TABLE),
+                                        errmsg("relation \"%s\" already exists, skipping",
+                                                       stmt->into->rel->relname)));
+                       return InvalidOid;
+               }
+       }
+
        /*
         * Create the tuple receiver object and insert info it will need
         */
index 6b1bf7be19daa1cd3f41d9a6ad10b75d88b7d2f8..491e4db9d6f7e77426a2e53cc901ebe7ac9779c6 100644 (file)
@@ -3317,6 +3317,7 @@ _copyCreateTableAsStmt(const CreateTableAsStmt *from)
        COPY_NODE_FIELD(into);
        COPY_SCALAR_FIELD(relkind);
        COPY_SCALAR_FIELD(is_select_into);
+       COPY_SCALAR_FIELD(if_not_exists);
 
        return newnode;
 }
index d5db71d3a86061d93b4beb598d5a916f3a74afb4..08036743d57e7bcea18e1536d3b0748c25dfbb24 100644 (file)
@@ -1530,6 +1530,7 @@ _equalCreateTableAsStmt(const CreateTableAsStmt *a, const CreateTableAsStmt *b)
        COMPARE_NODE_FIELD(into);
        COMPARE_SCALAR_FIELD(relkind);
        COMPARE_SCALAR_FIELD(is_select_into);
+       COMPARE_SCALAR_FIELD(if_not_exists);
 
        return true;
 }
index 4b5009b636dd7a944ffe5480e4e73dc15e3f39eb..1f4fe9d4943edc7c452e1804a0191eb40c328995 100644 (file)
@@ -3401,11 +3401,25 @@ CreateAsStmt:
                                        ctas->into = $4;
                                        ctas->relkind = OBJECT_TABLE;
                                        ctas->is_select_into = false;
+                                       ctas->if_not_exists = false;
                                        /* cram additional flags into the IntoClause */
                                        $4->rel->relpersistence = $2;
                                        $4->skipData = !($7);
                                        $$ = (Node *) ctas;
                                }
+               | CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS SelectStmt opt_with_data
+                               {
+                                       CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
+                                       ctas->query = $9;
+                                       ctas->into = $7;
+                                       ctas->relkind = OBJECT_TABLE;
+                                       ctas->is_select_into = false;
+                                       ctas->if_not_exists = true;
+                                       /* cram additional flags into the IntoClause */
+                                       $7->rel->relpersistence = $2;
+                                       $7->skipData = !($10);
+                                       $$ = (Node *) ctas;
+                               }
                ;
 
 create_as_target:
@@ -3444,11 +3458,25 @@ CreateMatViewStmt:
                                        ctas->into = $5;
                                        ctas->relkind = OBJECT_MATVIEW;
                                        ctas->is_select_into = false;
+                                       ctas->if_not_exists = false;
                                        /* cram additional flags into the IntoClause */
                                        $5->rel->relpersistence = $2;
                                        $5->skipData = !($8);
                                        $$ = (Node *) ctas;
                                }
+               | CREATE OptNoLog MATERIALIZED VIEW IF_P NOT EXISTS create_mv_target AS SelectStmt opt_with_data
+                               {
+                                       CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
+                                       ctas->query = $10;
+                                       ctas->into = $8;
+                                       ctas->relkind = OBJECT_MATVIEW;
+                                       ctas->is_select_into = false;
+                                       ctas->if_not_exists = true;
+                                       /* cram additional flags into the IntoClause */
+                                       $8->rel->relpersistence = $2;
+                                       $8->skipData = !($11);
+                                       $$ = (Node *) ctas;
+                               }
                ;
 
 create_mv_target:
index 5eaa435127343ba79e13f7c4c41827886666be59..458eeb0b9ec8f4eec10a57e9dc1a319c43b7a07a 100644 (file)
@@ -2652,6 +2652,7 @@ typedef struct CreateTableAsStmt
        IntoClause *into;                       /* destination table */
        ObjectType      relkind;                /* OBJECT_TABLE or OBJECT_MATVIEW */
        bool            is_select_into; /* it was written as SELECT INTO */
+       bool            if_not_exists;  /* just do nothing if it already exists? */
 } CreateTableAsStmt;
 
 /* ----------------------
index 167d02d039ec8774cfb7be803a48e734921590bc..35451d5af26774543a6b7ddbbbfa010fb9ba36e4 100644 (file)
@@ -218,3 +218,9 @@ CREATE TEMP TABLE pg_temp.doubly_temp (a int primary key);          -- also OK
 CREATE TEMP TABLE public.temp_to_perm (a int primary key);             -- not OK
 ERROR:  cannot create temporary relation in non-temporary schema
 DROP TABLE unlogged1, public.unlogged2;
+CREATE TABLE as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r';
+CREATE TABLE as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r';
+ERROR:  relation "as_select1" already exists
+CREATE TABLE IF NOT EXISTS as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r';
+NOTICE:  relation "as_select1" already exists, skipping
+DROP TABLE as_select1;
index b04510c599e98323b8b91af75280e4b4e2a6ad26..eb13ea75fb023e18de34406db218230ac59246b2 100644 (file)
@@ -508,6 +508,10 @@ SET ROLE user_dw;
 CREATE TABLE foo_data AS SELECT i, md5(random()::text)
   FROM generate_series(1, 10) i;
 CREATE MATERIALIZED VIEW mv_foo AS SELECT * FROM foo_data;
+CREATE MATERIALIZED VIEW mv_foo AS SELECT * FROM foo_data;
+ERROR:  relation "mv_foo" already exists
+CREATE MATERIALIZED VIEW IF NOT EXISTS mv_foo AS SELECT * FROM foo_data;
+NOTICE:  relation "mv_foo" already exists, skipping
 CREATE UNIQUE INDEX ON mv_foo (i);
 RESET ROLE;
 REFRESH MATERIALIZED VIEW mv_foo;
index 8eb246b817e968269ade39d28b4004dab56f24c2..08029a99b0a6a3e2439bad5d2a42d10c071bfa4e 100644 (file)
@@ -254,3 +254,8 @@ CREATE TEMP TABLE explicitly_temp (a int primary key);                      -- also OK
 CREATE TEMP TABLE pg_temp.doubly_temp (a int primary key);             -- also OK
 CREATE TEMP TABLE public.temp_to_perm (a int primary key);             -- not OK
 DROP TABLE unlogged1, public.unlogged2;
+
+CREATE TABLE as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r';
+CREATE TABLE as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r';
+CREATE TABLE IF NOT EXISTS as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r';
+DROP TABLE as_select1;
index fee1ddc8424726fe42721a9af8c1bdd6e0a552af..70e4492c1bb0c173238408525120ca3c844e6950 100644 (file)
@@ -201,6 +201,8 @@ SET ROLE user_dw;
 CREATE TABLE foo_data AS SELECT i, md5(random()::text)
   FROM generate_series(1, 10) i;
 CREATE MATERIALIZED VIEW mv_foo AS SELECT * FROM foo_data;
+CREATE MATERIALIZED VIEW mv_foo AS SELECT * FROM foo_data;
+CREATE MATERIALIZED VIEW IF NOT EXISTS mv_foo AS SELECT * FROM foo_data;
 CREATE UNIQUE INDEX ON mv_foo (i);
 RESET ROLE;
 REFRESH MATERIALIZED VIEW mv_foo;