Fix assertion if index is dropped during REFRESH CONCURRENTLY

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
This commit is contained in:
Heikki Linnakangas 2024-02-05 11:01:30 +02:00
parent 2699fc035a
commit add8bc9b8c
3 changed files with 38 additions and 2 deletions

View File

@ -795,9 +795,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.*) "

View 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()

View 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()