Fix busted Assert for CREATE MATVIEW ... WITH NO DATA.
authorTom Lane <[email protected]>
Thu, 11 Aug 2016 15:22:25 +0000 (11:22 -0400)
committerTom Lane <[email protected]>
Thu, 11 Aug 2016 15:22:25 +0000 (11:22 -0400)
Commit 874fe3aea changed the command tag returned for CREATE MATVIEW/CREATE
TABLE AS ... WITH NO DATA, but missed that there was code in spi.c that
expected the command tag to always be "SELECT".  Fortunately, the
consequence was only an Assert failure, so this oversight should have no
impact in production builds.

Since this code path was evidently un-exercised, add a regression test.

Per report from Shivam Saxena. Back-patch to 9.3, like the previous commit.

Michael Paquier

Report: <97218716-480B-4527-B5CD-D08D798A0C7B@dresources.com>

src/backend/executor/spi.c
src/test/regress/expected/matview.out
src/test/regress/sql/matview.sql

index b46b7074d70c4e0ee4d6a46bdc9aaed3fe2545e1..e6c8ad3e883943db111d1bb1fb477410d140f77f 100644 (file)
@@ -2180,15 +2180,23 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
                                 */
                                if (IsA(stmt, CreateTableAsStmt))
                                {
-                                       Assert(strncmp(completionTag, "SELECT ", 7) == 0);
-                                       _SPI_current->processed = strtoul(completionTag + 7,
-                                                                                                         NULL, 10);
+                                       CreateTableAsStmt *ctastmt = (CreateTableAsStmt *) stmt;
+
+                                       if (strncmp(completionTag, "SELECT ", 7) == 0)
+                                               _SPI_current->processed =
+                                                       strtoul(completionTag + 7, NULL, 10);
+                                       else
+                                       {
+                                               /* Must be a CREATE ... WITH NO DATA */
+                                               Assert(ctastmt->into->skipData);
+                                               _SPI_current->processed = 0;
+                                       }
 
                                        /*
                                         * For historical reasons, if CREATE TABLE AS was spelled
                                         * as SELECT INTO, return a special return code.
                                         */
-                                       if (((CreateTableAsStmt *) stmt)->is_select_into)
+                                       if (ctastmt->is_select_into)
                                                res = SPI_OK_SELINTO;
                                }
                                else if (IsA(stmt, CopyStmt))
index 2284e364ebffcf3f42b84cc5751673fd45840ab6..9f6795daf67d8dd116b67b612098828a765bec03 100644 (file)
@@ -477,3 +477,28 @@ SELECT * FROM mv_v;
 
 DROP TABLE v CASCADE;
 NOTICE:  drop cascades to materialized view mv_v
+-- make sure that create WITH NO DATA works via SPI
+BEGIN;
+CREATE FUNCTION mvtest_func()
+  RETURNS void AS $$
+BEGIN
+  CREATE MATERIALIZED VIEW mvtest1 AS SELECT 1 AS x;
+  CREATE MATERIALIZED VIEW mvtest2 AS SELECT 1 AS x WITH NO DATA;
+END;
+$$ LANGUAGE plpgsql;
+SELECT mvtest_func();
+ mvtest_func 
+-------------
+(1 row)
+
+SELECT * FROM mvtest1;
+ x 
+---
+ 1
+(1 row)
+
+SELECT * FROM mvtest2;
+ERROR:  materialized view "mvtest2" has not been populated
+HINT:  Use the REFRESH MATERIALIZED VIEW command.
+ROLLBACK;
index 280c4bb400e09f86b4632b7975bf61f5b048b025..bc10146a27fe4274e76334a88dd2d925b82ecb69 100644 (file)
@@ -166,3 +166,17 @@ DELETE FROM v WHERE EXISTS ( SELECT * FROM mv_v WHERE mv_v.a = v.a );
 SELECT * FROM v;
 SELECT * FROM mv_v;
 DROP TABLE v CASCADE;
+
+-- make sure that create WITH NO DATA works via SPI
+BEGIN;
+CREATE FUNCTION mvtest_func()
+  RETURNS void AS $$
+BEGIN
+  CREATE MATERIALIZED VIEW mvtest1 AS SELECT 1 AS x;
+  CREATE MATERIALIZED VIEW mvtest2 AS SELECT 1 AS x WITH NO DATA;
+END;
+$$ LANGUAGE plpgsql;
+SELECT mvtest_func();
+SELECT * FROM mvtest1;
+SELECT * FROM mvtest2;
+ROLLBACK;