Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Fix assertion if index is dropped during REFRESH CONCURRENTLY
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 5 Feb 2024 09:01:30 +0000 (11:01 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 5 Feb 2024 09:03:28 +0000 (11:03 +0200)
When assertions are disabled, the built SQL statement is invalid and
you get a "syntax error". So this isn't a serious problem, but let's
avoid the assertion failure.

Backpatch to all supported versions.

Reviewed-by: Noah Misch
src/backend/commands/matview.c
src/test/regress/expected/matview.out
src/test/regress/sql/matview.sql

index 03c9e97ca094f9d1e7a84baacbe24aa4cf7a8e61..a5f8972170b6c1fd3ef929530c711e81f73ff0a8 100644 (file)
@@ -804,9 +804,12 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
     *
     * ExecRefreshMatView() checks that after taking the exclusive lock on the
     * matview. So at least one unique index is guaranteed to exist here
-    * because the lock is still being held; so an Assert seems sufficient.
+    * because the lock is still being held.  (One known exception is if a
+    * function called as part of refreshing the matview drops the index.
+    * That's a pretty silly thing to do.)
     */
-   Assert(foundUniqueIndex);
+   if (!foundUniqueIndex)
+       elog(ERROR, "could not find suitable unique index on materialized view");
 
    appendStringInfoString(&querybuf,
                           " AND newdata.* OPERATOR(pg_catalog.*=) mv.*) "
index c109d97635b21912c8c5a8ff3eee2abdc8c86324..e811e1a049bf2f0d85bd1845df8ea2a88a1dffe3 100644 (file)
@@ -572,6 +572,22 @@ REFRESH MATERIALIZED VIEW mvtest_mv_foo;
 REFRESH MATERIALIZED VIEW CONCURRENTLY mvtest_mv_foo;
 DROP OWNED BY regress_user_mvtest CASCADE;
 DROP ROLE regress_user_mvtest;
+-- Concurrent refresh requires a unique index on the materialized
+-- view. Test what happens if it's dropped during the refresh.
+CREATE OR REPLACE FUNCTION mvtest_drop_the_index()
+  RETURNS bool AS $$
+BEGIN
+  EXECUTE 'DROP INDEX IF EXISTS mvtest_drop_idx';
+  RETURN true;
+END;
+$$ LANGUAGE plpgsql;
+CREATE MATERIALIZED VIEW drop_idx_matview AS
+  SELECT 1 as i WHERE mvtest_drop_the_index();
+NOTICE:  index "mvtest_drop_idx" does not exist, skipping
+CREATE UNIQUE INDEX mvtest_drop_idx ON drop_idx_matview (i);
+REFRESH MATERIALIZED VIEW CONCURRENTLY drop_idx_matview;
+ERROR:  could not find suitable unique index on materialized view
+DROP MATERIALIZED VIEW drop_idx_matview; -- clean up
 -- make sure that create WITH NO DATA works via SPI
 BEGIN;
 CREATE FUNCTION mvtest_func()
index 68b9ccfd4529964c2131b1d172dda803471daebf..543e0a6d73aa09f1c28a6dc2ff64890b4270d67b 100644 (file)
@@ -231,6 +231,23 @@ REFRESH MATERIALIZED VIEW CONCURRENTLY mvtest_mv_foo;
 DROP OWNED BY regress_user_mvtest CASCADE;
 DROP ROLE regress_user_mvtest;
 
+-- Concurrent refresh requires a unique index on the materialized
+-- view. Test what happens if it's dropped during the refresh.
+CREATE OR REPLACE FUNCTION mvtest_drop_the_index()
+  RETURNS bool AS $$
+BEGIN
+  EXECUTE 'DROP INDEX IF EXISTS mvtest_drop_idx';
+  RETURN true;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE MATERIALIZED VIEW drop_idx_matview AS
+  SELECT 1 as i WHERE mvtest_drop_the_index();
+
+CREATE UNIQUE INDEX mvtest_drop_idx ON drop_idx_matview (i);
+REFRESH MATERIALIZED VIEW CONCURRENTLY drop_idx_matview;
+DROP MATERIALIZED VIEW drop_idx_matview; -- clean up
+
 -- make sure that create WITH NO DATA works via SPI
 BEGIN;
 CREATE FUNCTION mvtest_func()