Fix handling of REFRESH MATERIALIZED VIEW CONCURRENTLY
authorPavan Deolasee <pavan.deolasee@gmail.com>
Tue, 17 Jul 2018 05:50:59 +0000 (11:20 +0530)
committerPavan Deolasee <pavan.deolasee@gmail.com>
Tue, 17 Jul 2018 05:50:59 +0000 (11:20 +0530)
We create a coordinator-only LOCAL temporary table for REFRESH MATERIALIZED
VIEW CONCURRENTLY. Since this table does not exist on the remote nodes, we must
not use explicit "ANALYZE <temptable>". Instead, just analyze it locally like
we were doing at other places.

Restore the matview test case to use REFRESH MATERIALIZED VIEW CONCURRENTLY now
that the underlying bug is fixed.

src/backend/commands/matview.c
src/test/regress/expected/matview.out
src/test/regress/sql/matview.sql

index e6974443620c2968d4d98a95de953be52d31908d..bf5a72d5f918421f2714277d893e9cd14f48ba74 100644 (file)
@@ -557,6 +557,8 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
        char       *matviewname;
        char       *tempname;
        char       *diffname;
+       char       *qualified_diffname;
+       char       *tempschema;
        TupleDesc       tupdesc;
        bool            foundUniqueIndex;
        List       *indexoidlist;
@@ -569,9 +571,11 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
        matviewname = quote_qualified_identifier(get_namespace_name(RelationGetNamespace(matviewRel)),
                                                                                RelationGetRelationName(matviewRel));
        tempRel = heap_open(tempOid, NoLock);
-       tempname = quote_qualified_identifier(get_namespace_name(RelationGetNamespace(tempRel)),
+       tempschema = get_namespace_name(RelationGetNamespace(tempRel));
+       tempname = quote_qualified_identifier(tempschema,
                                                                                  RelationGetRelationName(tempRel));
-       diffname = make_temptable_name_n(tempname, 2);
+       diffname = make_temptable_name_n(RelationGetRelationName(tempRel), 2);
+       qualified_diffname = quote_qualified_identifier(tempschema, diffname);
 
        relnatts = matviewRel->rd_rel->relnatts;
        usedForQual = (bool *) palloc0(sizeof(bool) * relnatts);
@@ -661,7 +665,8 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
 #endif                                  
                                         "SELECT mv.ctid AS tid, newdata "
                                         "FROM %s mv FULL JOIN %s newdata ON (",
-                                        diffname, matviewname, tempname);
+                                        qualified_diffname,
+                                        matviewname, tempname);
 
        /*
         * Get the list of index OIDs for the table from the relcache, and look up
@@ -761,11 +766,25 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
         * must keep it around because its type is referenced from the diff table.
         */
 
+#ifndef PGXC
        /* Analyze the diff table. */
        resetStringInfo(&querybuf);
-       appendStringInfo(&querybuf, "ANALYZE %s", diffname);
+       appendStringInfo(&querybuf, "ANALYZE %s", qualified_diffname);
        if (SPI_exec(querybuf.data, 0) != SPI_OK_UTILITY)
                elog(ERROR, "SPI_exec failed: %s", querybuf.data);
+#else
+       {
+               /*
+                * Don't want to send down the ANALYZE on the remote nodes because the
+                * temporary table was not created there to start with. See above.
+                */
+               VacuumStmt *stmt = makeNode(VacuumStmt);
+               RangeVar *rv = makeRangeVar(tempschema, diffname, -1);
+               stmt->relation = rv;
+               stmt->options = VACOPT_ANALYZE;
+               ExecVacuum(stmt, true);
+       }
+#endif
 
        OpenMatViewIncrementalMaintenance();
 
@@ -776,7 +795,8 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
                                         "(SELECT diff.tid FROM %s diff "
                                         "WHERE diff.tid IS NOT NULL "
                                         "AND diff.newdata IS NULL)",
-                                        matviewname, diffname);
+                                        matviewname,
+                                        qualified_diffname);
        if (SPI_exec(querybuf.data, 0) != SPI_OK_DELETE)
                elog(ERROR, "SPI_exec failed: %s", querybuf.data);
 
@@ -785,7 +805,8 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
        appendStringInfo(&querybuf,
                                         "INSERT INTO %s SELECT (diff.newdata).* "
                                         "FROM %s diff WHERE tid IS NULL",
-                                        matviewname, diffname);
+                                        matviewname,
+                                        qualified_diffname);
        if (SPI_exec(querybuf.data, 0) != SPI_OK_INSERT)
                elog(ERROR, "SPI_exec failed: %s", querybuf.data);
 
@@ -796,7 +817,8 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
 
        /* Clean up temp tables. */
        resetStringInfo(&querybuf);
-       appendStringInfo(&querybuf, "DROP TABLE %s, %s", diffname, tempname);
+       appendStringInfo(&querybuf, "DROP TABLE %s, %s",
+                       qualified_diffname, tempname);
        if (SPI_exec(querybuf.data, 0) != SPI_OK_UTILITY)
                elog(ERROR, "SPI_exec failed: %s", querybuf.data);
 
index 8d4c02be3558302391d23cd121cf7ec8d3c0c978..0d2e2c35bae97b80aa0a48c6731617a5ba9bdfb5 100644 (file)
@@ -194,13 +194,14 @@ SELECT * FROM tvm ORDER BY type;
  z    |     11
 (3 rows)
 
+REFRESH MATERIALIZED VIEW CONCURRENTLY tm;
 REFRESH MATERIALIZED VIEW tvm;
 SELECT * FROM tm ORDER BY type;
  type | totamt 
 ------+--------
  x    |      5
  y    |     12
- z    |     11
+ z    |     24
 (3 rows)
 
 SELECT * FROM tvm ORDER BY type;
@@ -282,7 +283,7 @@ EXPLAIN (costs off)
 SELECT * FROM tmm;
  grandtot 
 ----------
-       28
+       41
 (1 row)
 
 SELECT * FROM tvmm;
@@ -312,7 +313,7 @@ SELECT type, m.totamt AS mtot, v.totamt AS vtot FROM tm m LEFT JOIN tv v USING (
 ------+------+------
  x    |    5 |    5
  y    |   12 |   12
- z    |   11 |   24
+ z    |   24 |   24
 (3 rows)
 
 -- make sure that dependencies are reported properly when they block the drop
@@ -398,6 +399,9 @@ INSERT INTO foo SELECT * FROM foo;
 REFRESH MATERIALIZED VIEW mv;
 ERROR:  could not create unique index "mv_a_idx"
 DETAIL:  Key (a)=(1) is duplicated.
+REFRESH MATERIALIZED VIEW CONCURRENTLY mv;
+ERROR:  new data for materialized view "mv" contains duplicate rows without any null columns
+DETAIL:  Row: (1,10)
 DROP TABLE foo CASCADE;
 NOTICE:  drop cascades to materialized view mv
 -- make sure that all columns covered by unique indexes works
@@ -409,6 +413,7 @@ CREATE UNIQUE INDEX on mv (c);
 INSERT INTO foo VALUES(2, 3, 4);
 INSERT INTO foo VALUES(3, 4, 5);
 REFRESH MATERIALIZED VIEW mv;
+REFRESH MATERIALIZED VIEW CONCURRENTLY mv;
 DROP TABLE foo CASCADE;
 NOTICE:  drop cascades to materialized view mv
 -- allow subquery to reference unpopulated matview if WITH NO DATA is specified
@@ -426,16 +431,18 @@ INSERT INTO boxes (b) VALUES
 CREATE MATERIALIZED VIEW boxmv AS SELECT * FROM boxes;
 CREATE UNIQUE INDEX boxmv_id ON boxmv (id);
 UPDATE boxes SET b = '(2,2),(1,1)' WHERE id = 2;
+REFRESH MATERIALIZED VIEW CONCURRENTLY boxmv;
 SELECT * FROM boxmv ORDER BY id;
  id |              b              
 ----+-----------------------------
   1 | (32,32),(31,31)
-  2 | (2.0000004,2.0000004),(1,1)
+  2 | (2,2),(1,1)
   3 | (1.9999996,1.9999996),(1,1)
 (3 rows)
 
 DROP TABLE boxes CASCADE;
 NOTICE:  drop cascades to materialized view boxmv
+-- make sure that column names are handled correctly
 CREATE TABLE mvtest_v (i int, j int);
 CREATE MATERIALIZED VIEW mvtest_mv_v (ii, jj, kk) AS SELECT i, j FROM mvtest_v; -- error
 ERROR:  too many column names were specified
@@ -450,7 +457,7 @@ INSERT INTO mvtest_v values (1, 2);
 CREATE UNIQUE INDEX mvtest_mv_v_ii ON mvtest_mv_v (ii);
 REFRESH MATERIALIZED VIEW mvtest_mv_v;
 UPDATE mvtest_v SET j = 3 WHERE x = 1;
--- REFRESH MATERIALIZED VIEW CONCURRENTLY mvtest_mv_v;
+REFRESH MATERIALIZED VIEW CONCURRENTLY mvtest_mv_v;
 REFRESH MATERIALIZED VIEW mvtest_mv_v_2;
 REFRESH MATERIALIZED VIEW mvtest_mv_v_3;
 REFRESH MATERIALIZED VIEW mvtest_mv_v_4;
@@ -463,7 +470,7 @@ SELECT * FROM mvtest_v;
 SELECT * FROM mvtest_mv_v;
  ii | jj 
 ----+----
-  1 |  2
+  1 |  3
 (1 row)
 
 SELECT * FROM mvtest_mv_v_2;
@@ -543,6 +550,7 @@ NOTICE:  relation "mv_foo" already exists, skipping
 CREATE UNIQUE INDEX ON mv_foo (i);
 RESET ROLE;
 REFRESH MATERIALIZED VIEW mv_foo;
+REFRESH MATERIALIZED VIEW CONCURRENTLY mv_foo;
 DROP OWNED BY user_dw CASCADE;
 DROP ROLE user_dw;
 -- make sure that create WITH NO DATA works via SPI
index 45634f405335ddd79bbb96c2e22b4c9ed70c210a..cef1176c1092ddcae398cb3c477247d289a23db5 100644 (file)
@@ -59,6 +59,7 @@ INSERT INTO t VALUES (6, 'z', 13);
 -- confirm pre- and post-refresh contents of fairly simple materialized views
 SELECT * FROM tm ORDER BY type;
 SELECT * FROM tvm ORDER BY type;
+REFRESH MATERIALIZED VIEW CONCURRENTLY tm;
 REFRESH MATERIALIZED VIEW tvm;
 SELECT * FROM tm ORDER BY type;
 SELECT * FROM tvm ORDER BY type;
@@ -127,6 +128,7 @@ CREATE MATERIALIZED VIEW mv AS SELECT * FROM foo;
 CREATE UNIQUE INDEX ON mv(a);
 INSERT INTO foo SELECT * FROM foo;
 REFRESH MATERIALIZED VIEW mv;
+REFRESH MATERIALIZED VIEW CONCURRENTLY mv;
 DROP TABLE foo CASCADE;
 
 -- make sure that all columns covered by unique indexes works
@@ -138,6 +140,7 @@ CREATE UNIQUE INDEX on mv (c);
 INSERT INTO foo VALUES(2, 3, 4);
 INSERT INTO foo VALUES(3, 4, 5);
 REFRESH MATERIALIZED VIEW mv;
+REFRESH MATERIALIZED VIEW CONCURRENTLY mv;
 DROP TABLE foo CASCADE;
 
 -- allow subquery to reference unpopulated matview if WITH NO DATA is specified
@@ -155,10 +158,11 @@ INSERT INTO boxes (b) VALUES
 CREATE MATERIALIZED VIEW boxmv AS SELECT * FROM boxes;
 CREATE UNIQUE INDEX boxmv_id ON boxmv (id);
 UPDATE boxes SET b = '(2,2),(1,1)' WHERE id = 2;
+REFRESH MATERIALIZED VIEW CONCURRENTLY boxmv;
 SELECT * FROM boxmv ORDER BY id;
 DROP TABLE boxes CASCADE;
 
-
+-- make sure that column names are handled correctly
 CREATE TABLE mvtest_v (i int, j int);
 CREATE MATERIALIZED VIEW mvtest_mv_v (ii, jj, kk) AS SELECT i, j FROM mvtest_v; -- error
 CREATE MATERIALIZED VIEW mvtest_mv_v (ii, jj) AS SELECT i, j FROM mvtest_v; -- ok
@@ -171,7 +175,7 @@ INSERT INTO mvtest_v values (1, 2);
 CREATE UNIQUE INDEX mvtest_mv_v_ii ON mvtest_mv_v (ii);
 REFRESH MATERIALIZED VIEW mvtest_mv_v;
 UPDATE mvtest_v SET j = 3 WHERE x = 1;
--- REFRESH MATERIALIZED VIEW CONCURRENTLY mvtest_mv_v;
+REFRESH MATERIALIZED VIEW CONCURRENTLY mvtest_mv_v;
 REFRESH MATERIALIZED VIEW mvtest_mv_v_2;
 REFRESH MATERIALIZED VIEW mvtest_mv_v_3;
 REFRESH MATERIALIZED VIEW mvtest_mv_v_4;
@@ -207,6 +211,7 @@ 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;
+REFRESH MATERIALIZED VIEW CONCURRENTLY mv_foo;
 DROP OWNED BY user_dw CASCADE;
 DROP ROLE user_dw;